diff --git a/.gitignore b/.gitignore
index 3a9be36e5..c6ffd662d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,110 +1,111 @@
 *.swp
 Makefile.in
 aclocal.m4
 autoconf
 autoheader
 autom4te.cache
 automake
 autoscan.log
 compile
 configure
 configure.scan
 config.guess
 config.log
 config.sub
 config.status
 Makefile
 depcomp
 install-sh
 libtoolize
 ltmain.sh
 libtool
 make/stamp-h1
 m4
 make/clusterautoconfig.h*
 missing
 *.pc
 .deps
 .libs
 *.o
 *.la
 *.lo
 *.loT
 rgmanager/src/resources/fs.sh
 rgmanager/src/resources/oracledb.sh
 rgmanager/src/resources/utils/config-utils.sh
 resource-agents-*
 .version
 
 # generated by ./autogen.sh && ./configure
 doc/man/*.7
 doc/man/*.xml
 heartbeat/ocf-binaries
 heartbeat/ocf-directories
 heartbeat/ocf-shellfuncs
 heartbeat/send_ua
 heartbeat/shellfuncs
 heartbeat/*.pyc
 include/agent_config.h
 include/config.h
 include/config.h.in
 include/stamp-h1
 include/stamp-h2
 ldirectord/ldirectord
 ldirectord/ldirectord.8
 ldirectord/OCF/ldirectord
 ldirectord/init.d/ldirectord
 ldirectord/init.d/ldirectord.debian
 ldirectord/init.d/ldirectord.debian.default
 ldirectord/systemd/ldirectord.service
 tools/findif
 tools/ocf-tester
 tools/send_arp
 tools/tickle_tcp
 tools/ocft/README
 tools/ocft/README.zh_CN
 tools/ocft/caselib
 tools/ocft/ocft
 
 *.cache
 *.upgrade.xml
 py-compile
 ylwrap
+__pycache__
 
 # BEAM Entries
 *.beam
 parser-messages
 MISC_ERRORS
 cscope.files
 cscope.out
 patches
 updates
 logs
 
 # OS and Editor Artifacts
 .DS_Store
 .bomb
 *.rej
 *.bz2
 *.gz
 *.xz
 *.sed
 *.diff
 *.patch
 *.gres
 *~
 
 # Misc
 HTML
 TAGS
 GPATH
 GRTAGS
 GSYMS
 GTAGS
 .gres.*
 *.orig
 .gdb_history
 *~ 
 \#*
 .changes
 pacemaker.tar.gz
diff --git a/heartbeat/Squid.in b/heartbeat/Squid.in
index b992909f9..ee5cd5a28 100644
--- a/heartbeat/Squid.in
+++ b/heartbeat/Squid.in
@@ -1,446 +1,453 @@
 #!@BASH_SHELL@
 #
 # Description:  Manages a Squid Server provided by NTT OSSC as an 
 #               OCF High-Availability resource under Heartbeat/LinuxHA control
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 #
 # Copyright (c) 2008 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
 #
 #######################################################################
 # OCF parameters:
 #   OCF_RESKEY_squid_exe    : Executable file
 #   OCF_RESKEY_squid_conf   : Configuration file
 #   OCF_RESKEY_squid_pidfile: Process id file
 #   OCF_RESKEY_squid_port   : Port number
 #   OCF_RESKEY_debug_mode   : Debug mode
 #   OCF_RESKEY_debug_log    : Debug log file
 #   OCF_RESKEY_squid_stop_timeout:
 #                             Number of seconds to await to confirm a
 #                             normal stop method
 #
 #   OCF_RESKEY_squid_exe, OCF_RESKEY_squid_conf, OCF_RESKEY_squid_pidfile
 #   and OCF_RESKEY_squid_port must be specified. Each of the rests
 #   has its default value or refers OCF_RESKEY_squid_conf to make
 #   its value when no explicit value is given.
 ###############################################################################
 
 : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
 . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
 
 usage() 
 {
 	cat <<-!
 usage: $0 action
 
 action:
         start       : start a new squid instance
 
         stop        : stop the running squid instance
 
         status      : return the status of squid, run or down
 
         monitor     : return TRUE if the squid appears to be working.
 
         meta-data   : show meta data message
 
         validate-all: validate the instance parameters
 !
 	return $OCF_ERR_ARGS
 }
 
 metadata_squid()
 {
     cat <<END
 <?xml version="1.0"?>
 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
 <resource-agent name="Squid">
 <version>1.0</version>
 
 <longdesc lang="en">
 The resource agent of Squid.
 This manages a Squid instance as an HA resource.
 </longdesc>
 <shortdesc lang="en">Manages a Squid proxy server instance</shortdesc>
 
 <parameters>
 
 <parameter name="squid_exe" required="1" unique="0">
 <longdesc lang="en">
 This is a required parameter. This parameter specifies squid's
 executable file.
 </longdesc>
 <shortdesc lang="en">Executable file</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="squid_conf" required="1" unique="1">
 <longdesc lang="en">
 This is a required parameter. This parameter specifies a configuration file
 for a squid instance managed by this RA.
 </longdesc>
 <shortdesc lang="en">Configuration file</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="squid_pidfile" required="1" unique="1">
 <longdesc lang="en">
 This is a required parameter. This parameter specifies a process id file
 for a squid instance managed by this RA.
 </longdesc>
 <shortdesc lang="en">Pidfile</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="squid_port" required="1" unique="1">
 <longdesc lang="en">
 This is a required parameter. This parameter specifies a port number
 for a squid instance managed by this RA. If multiple ports are used,
 you must specify only one of them.
 </longdesc>
 <shortdesc lang="en">Port number</shortdesc>
 <content type="integer" default=""/>
 </parameter>
 
 <parameter name="squid_stop_timeout" unique="0">
 <longdesc lang="en">
 On stop, a squid shutdown is invoked first. If the resource
 doesn't stop within this timeout, we resort to stopping
 processes by sending signals and finally KILLing them.
 </longdesc>
 <shortdesc lang="en">how long to wait for squid shutdown to stop the
 instance before resorting to kill</shortdesc>
 <content type="integer" default="10"/>
 </parameter>
 
 <parameter name="debug_mode" unique="0">
 <longdesc lang="en">
 This is an optional parameter.
 This RA runs in debug mode when this parameter includes 'x' or 'v'.
 If 'x' is included, both of STDOUT and STDERR redirect to the logfile
 specified by "debug_log", and then the builtin shell option 'x' is turned on.
 It is similar about 'v'.
 </longdesc>
 <shortdesc lang="en">Debug mode</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="debug_log" unique="0">
 <longdesc lang="en">
 This is an optional and omittable parameter.
 This parameter specifies a destination file for debug logs
 and works only if this RA run in debug mode.  Refer to "debug_mode"
 about debug mode. If no value is given but it's requied, it's made by the
 following rules: "/var/log/" as a directory part, the basename of
 the configuration file given by "syslog_ng_conf" as a basename part,
 ".log" as a suffix.
 </longdesc>
 <shortdesc lang="en">A destination of the debug log</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 </parameters>
 
 <actions>
 <action name="start" timeout="60s" />
 <action name="stop" timeout="120s" />
 <action name="status" timeout="60s" />
 <action name="monitor" depth="0" timeout="30s" interval="10s" />
 <action name="meta-data" timeout="5s" />
 <action name="validate-all"  timeout="5s"/>
 </actions>
 </resource-agent>
 END
 
 	return $OCF_SUCCESS
 }
 
 get_pids()
 {
 	SQUID_PIDS=( )
 
 	# Seek by pattern
 	SQUID_PIDS[0]=$(pgrep -f "$PROCESS_PATTERN")
 
 	# Seek by pidfile
 	SQUID_PIDS[1]=$(awk '1{print $1}' $SQUID_PIDFILE 2>/dev/null)
 
 	if [[ -n "${SQUID_PIDS[1]}" ]]; then
 		typeset exe
 		exe=$(ls -l "/proc/${SQUID_PIDS[1]}/exe")
 		if [[ $? = 0 ]]; then
 			exe=${exe##*-> }
 			if ! [[ "$exe" = $SQUID_EXE ]]; then
 				SQUID_PIDS[1]=""
 			fi
 		else
 			SQUID_PIDS[1]=""
 		fi
 	fi
 
 	# Seek by port
-	SQUID_PIDS[2]=$(
-		netstat -apn |
-		awk '/tcp.*:'$SQUID_PORT' .*LISTEN/ && $7~/^[1-9]/ {
-			sub("\\/.*", "", $7); print $7; exit}')
+	if have_binary netstat; then
+		SQUID_PIDS[2]=$(
+			netstat -apn |
+			awk '/tcp.*:'$SQUID_PORT' .*LISTEN/ && $7~/^[1-9]/ {
+				sub("\\/.*", "", $7); print $7; exit}')
+	else
+		SQUID_PIDS[2]=$(
+			ss -apn |
+			awk '/tcp.*LISTEN.*:'$SQUID_PORT'/ {
+				sub(".*pid=", "", $7); sub(",fd=.*", "", $7); print $7 }')
+	fi
 }
 
 are_all_pids_found()
 {
 	if 
 		[[ -n "${SQUID_PIDS[0]}" ]] &&
 		[[ -n "${SQUID_PIDS[1]}" ]] &&
 		[[ -n "${SQUID_PIDS[2]}" ]]
 	then
 		return 0
 	else
 		return 1
 	fi
 }
 
 are_pids_sane()
 {
 	if [[ "${SQUID_PIDS[1]}" = "${SQUID_PIDS[2]}" ]]; then
 		return $OCF_SUCCESS
 	else
 		ocf_exit_reason "$SQUID_NAME:Pid unmatch"
 		return $OCF_ERR_GENERIC
 	fi
 }
 
 is_squid_dead()
 {
 	if 
 		[[ -z "${SQUID_PIDS[0]}" ]] &&
 		[[ -z "${SQUID_PIDS[2]}" ]]
 	then
 		return 0
 	else
 		return 1
 	fi
 }
 
 monitor_squid()
 {
 	typeset trialcount=0
 
 	while true; do
 		get_pids
 
 		if are_all_pids_found; then
 			are_pids_sane
 			return $OCF_SUCCESS
 		fi
 
 		if is_squid_dead; then
 			return $OCF_NOT_RUNNING
 		fi
 
 		ocf_log info "$SQUID_NAME:Inconsistent processes:" \
 			"${SQUID_PIDS[0]},${SQUID_PIDS[1]},${SQUID_PIDS[2]}"
 		(( trialcount = trialcount + 1 ))
 		if (( trialcount > SQUID_CONFIRM_TRIALCOUNT )); then
 			ocf_exit_reason "$SQUID_NAME:Inconsistency of processes remains unsolved"
 			return $OCF_ERR_GENERIC
 		fi
 		sleep 1
 	done
 }
 
 start_squid()
 {
 	typeset status
 
 	monitor_squid
 	status=$?
 
 	if [[ $status != $OCF_NOT_RUNNING ]]; then
 		return $status
 	fi
 
 	set -- "$SQUID_OPTS"
 	ocf_run $SQUID_EXE -f "$SQUID_CONF" "$@"
 	status=$?
 	if [[ $status != $OCF_SUCCESS ]]; then
 		return $OCF_ERR_GENERIC
 	fi
 
 	while true; do
 		get_pids
 		if are_all_pids_found && are_pids_sane; then
 			return $OCF_SUCCESS
 		fi
 		ocf_log info "$SQUID_NAME:Waiting for squid to be invoked"
 		sleep 1
 	done
 
 	return $OCF_ERR_GENERIC
 }
 
 stop_squid()
 {
 	typeset lapse_sec
 
 	if ocf_run $SQUID_EXE -f $SQUID_CONF -k shutdown; then
 		lapse_sec=0
 		while true; do
 			get_pids
 			if is_squid_dead; then
 				rm -f $SQUID_PIDFILE
 				return $OCF_SUCCESS
 			fi
 			(( lapse_sec = lapse_sec + 1 ))
 			if (( lapse_sec > SQUID_STOP_TIMEOUT )); then
 				break
 			fi
 			sleep 1
 			ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \
 				"stop NORM $lapse_sec/$SQUID_STOP_TIMEOUT"
 		done
 	fi
 
 	while true; do
 		get_pids
 		ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \
 			"try to stop by SIGKILL:${SQUID_PIDS[0]} ${SQUID_PIDS[2]}"
 		kill -KILL ${SQUID_PIDS[0]} ${SQUID_PIDS[2]}
 		sleep 1
 		if is_squid_dead; then
 			rm -f $SQUID_PIDFILE
 			return $OCF_SUCCESS
 		fi
 	done
 
 	return $OCF_ERR_GENERIC
 }
 
 status_squid()
 {
 	return $OCF_SUCCESS
 }
 
 
 validate_all_squid()
 {
 	ocf_log info "validate_all_squid[$SQUID_NAME]"
 	return $OCF_SUCCESS
 }
 
 : === Debug ${0##*/} $1 ===
 
 if [[ "$1" = "meta-data" ]]; then
 	metadata_squid
 	exit $?
 fi
 
 SQUID_CONF="${OCF_RESKEY_squid_conf}"
 if [[ -z "$SQUID_CONF" ]]; then
 	ocf_exit_reason "SQUID_CONF is not defined"
 	exit $OCF_ERR_CONFIGURED
 fi
 
 SQUID_NAME="${SQUID_CONF##*/}"
 SQUID_NAME="${SQUID_NAME%.*}"
 
 DEBUG_LOG="${OCF_RESKEY_debug_log-/var/log/squid_${SQUID_NAME}_debug}.log"
 
 DEBUG_MODE=""
 case $OCF_RESKEY_debug_mode in
 	*x*) DEBUG_MODE="${DEBUG_MODE}x";;
 esac
 case $OCF_RESKEY_debug_mode in
 	*v*) DEBUG_MODE="${DEBUG_MODE}v";;
 esac
 
 if [ -n "$DEBUG_MODE" ]; then
 	PS4='\d \t \h '"${1-unknown} "
 	export PS4
 	exec 1>>$DEBUG_LOG 2>&1
 	set -$DEBUG_MODE
 fi
 
 SQUID_EXE="${OCF_RESKEY_squid_exe}"
 if [[ -z "$SQUID_EXE" ]]; then
 	ocf_exit_reason "SQUID_EXE is not defined"
 	exit $OCF_ERR_CONFIGURED
 fi
 if [[ ! -x "$SQUID_EXE" ]]; then
 	ocf_exit_reason "$SQUID_EXE is not found"
 	exit $OCF_ERR_CONFIGURED
 fi
 
 SQUID_PIDFILE="${OCF_RESKEY_squid_pidfile}"
 if [[ -z "$SQUID_PIDFILE" ]]; then
 	ocf_exit_reason "SQUID_PIDFILE is not defined"
 	exit $OCF_ERR_CONFIGURED
 fi
 
 SQUID_PORT="${OCF_RESKEY_squid_port}"
 if [[ -z "$SQUID_PORT" ]]; then
 	ocf_exit_reason "SQUID_PORT is not defined"
 	exit $OCF_ERR_CONFIGURED
 fi
 
 SQUID_OPTS="${OCF_RESKEY_squid_opts}"
 
 SQUID_PIDS=( )
 
 SQUID_CONFIRM_TRIALCOUNT="${OCF_RESKEY_squid_confirm_trialcount-3}"
 
 SQUID_STOP_TIMEOUT="${OCF_RESKEY_squid_stop_timeout-10}"
 SQUID_SUSPEND_TRIALCOUNT="${OCF_RESKEY_squid_suspend_trialcount-10}"
 
 PROCESS_PATTERN="$SQUID_EXE -f $SQUID_CONF"
 
 COMMAND=$1
 
 case "$COMMAND" in
 	start)
 		ocf_log debug  "[$SQUID_NAME] Enter squid start"
 		start_squid
 		func_status=$?
 		ocf_log debug  "[$SQUID_NAME] Leave squid start $func_status"
 		exit $func_status
 		;;
 	stop)
 		ocf_log debug  "[$SQUID_NAME] Enter squid stop"
 		stop_squid
 		func_status=$?
 		ocf_log debug  "[$SQUID_NAME] Leave squid stop $func_status"
 		exit $func_status
 		;;
 	status)
 		status_squid
 		exit $?
 		;;
 	monitor)
 		#ocf_log debug  "[$SQUID_NAME] Enter squid monitor"
 		monitor_squid
 		func_status=$?
 		#ocf_log debug  "[$SQUID_NAME] Leave squid monitor $func_status"
 		exit $func_status
 		;;
 	validate-all)
 		validate_all_squid
 		exit $?
 		;;
 	*)
 		usage
 		;;
 esac
 
 # vim: set sw=4 ts=4 :
 
diff --git a/heartbeat/garbd b/heartbeat/garbd
index aa0cea45f..b88d448fb 100755
--- a/heartbeat/garbd
+++ b/heartbeat/garbd
@@ -1,417 +1,430 @@
 #!/bin/sh
 #
 # Copyright (c) 2015 Damien Ciabrini <dciabrin@redhat.com>
 #                    All Rights Reserved.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of version 2 of the GNU General Public License as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it would be useful, but
 # WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 #
 # Further, this software is distributed without any warranty that it is
 # free of the rightful claim of any third person regarding infringement
 # or the like.  Any license provided herein, whether implied or
 # otherwise, applies only to this software file.  Patent licenses, if
 # any, provided herein do not apply to combinations of this program with
 # other software, or any other product whatsoever.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write the Free Software Foundation,
 # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 #
 
 ##
 # README.
 #
 # Resource agent for garbd, the Galera arbitrator
 #
 # You can use this agent if you run an even number of galera nodes,
 # and you want an additional node to avoid split-brain situations.
 #
 # garbd requires that a Galera cluster is running, so make sure to
 # add a proper ordering constraint to the cluster, e.g.:
 #
 #   pcs constraint order galera-master then garbd
 #
 # If you add garbd to the cluster while Galera is not running, you
 # might want to disable it before setting up ordering constraint, e.g.:
 #
 #   pcs resource create garbd garbd \
 #      wsrep_cluster_address=gcomm://node1:4567,node2:4567 \
 #      meta target-role=stopped
 #
 # Use location constraints to avoid running galera and garbd on
 # the same node, e.g.:
 #
 #   pcs constraint colocation add garbd with galera-master -INFINITY
 #   pcs constraint location garbd prefers node3=INFINITY
 #
 ##
 
 #######################################################################
 # Initialization:
 
 : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
 . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
 
 #######################################################################
 # Set default paramenter values
 
 OCF_RESKEY_binary_default="/usr/sbin/garbd"
 OCF_RESKEY_log_default="/var/log/garbd.log"
 OCF_RESKEY_pid_default="/var/run/garbd.pid"
 OCF_RESKEY_user_default="mysql"
 if [ "X${HOSTOS}" = "XOpenBSD" ];then
     OCF_RESKEY_group_default="_mysql"
 else
     OCF_RESKEY_group_default="mysql"
 fi
 
 : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
 : ${OCF_RESKEY_log=${OCF_RESKEY_log_default}}
 : ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
 : ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
 : ${OCF_RESKEY_group=${OCF_RESKEY_group_default}}
 
 usage() {
   cat <<UEND
 usage: $0 (start|stop|validate-all|meta-data|status|monitor)
 
 $0 manages a Galera arbitrator.
 
 The 'start' operation starts the arbitrator.
 The 'stop' operation stops the arbitrator.
 The 'status' operation reports whether the arbitrator is running
 The 'monitor' operation reports whether the arbitrator seems to be working
 The 'validate-all' operation reports whether the parameters are valid
 
 UEND
 }
 
 meta_data() {
    cat <<END
 <?xml version="1.0"?>
 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
 <resource-agent name="garbd">
 <version>1.0</version>
 
 <longdesc lang="en">
 Resource script for managing Galera arbitrator.
 </longdesc>
 <shortdesc lang="en">Manages a galera arbitrator instance</shortdesc>
 <parameters>
 
 <parameter name="binary" unique="0" required="0">
 <longdesc lang="en">
 Location of the Galera arbitrator binary
 </longdesc>
 <shortdesc lang="en">garbd server binary</shortdesc>
 <content type="string" default="${OCF_RESKEY_binary_default}" />
 </parameter>
 
 <parameter name="user" unique="0" required="0">
 <longdesc lang="en">
 User running the garbd process
 </longdesc>
 <shortdesc lang="en">garbd user</shortdesc>
 <content type="string" default="${OCF_RESKEY_user_default}" />
 </parameter>
 
 <parameter name="group" unique="0" required="0">
 <longdesc lang="en">
 Group running garbd (for logfile permissions)
 </longdesc>
 <shortdesc lang="en">garbd group</shortdesc>
 <content type="string" default="${OCF_RESKEY_group_default}"/>
 </parameter>
 
 <parameter name="log" unique="0" required="0">
 <longdesc lang="en">
 The logfile to be used for garbd.
 </longdesc>
 <shortdesc lang="en">Galera arbitrator log file</shortdesc>
 <content type="string" default="${OCF_RESKEY_log_default}"/>
 </parameter>
 
 <parameter name="pid" unique="0" required="0">
 <longdesc lang="en">
 The pidfile to be used for garbd.
 </longdesc>
 <shortdesc lang="en">Galera arbitrator pidfile</shortdesc>
 <content type="string" default="${OCF_RESKEY_pid_default}"/>
 </parameter>
 
 <parameter name="options" unique="0" required="0">
 <longdesc lang="en">
 Additional parameters which are passed to garbd on startup.
 </longdesc>
 <shortdesc lang="en">Additional parameters to pass to garbd</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="wsrep_cluster_address" unique="0" required="1">
 <longdesc lang="en">
 The galera cluster address. This takes the form of:
 gcomm://node:port,node:port,node:port
 
 Unlike Galera servers, port is mandatory for garbd.
 </longdesc>
 <shortdesc lang="en">Galera cluster address</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 <parameter name="wsrep_cluster_name" unique="0" required="1">
 <longdesc lang="en">
 The group name of the Galera cluster to connect to.
 </longdesc>
 <shortdesc lang="en">Galera cluster name</shortdesc>
 <content type="string" default=""/>
 </parameter>
 
 </parameters>
 
 <actions>
 <action name="start" timeout="20s" />
 <action name="stop" timeout="20s" />
 <action name="monitor" depth="0" timeout="20s" interval="20s" />
 <action name="validate-all" timeout="5s" />
 <action name="meta-data" timeout="5s" />
 </actions>
 </resource-agent>
 END
 }
 
 
 garbd_start()
 {
     local rc
     local pid
     local start_wait
     local garbd_params
 
     garbd_status info
     rc=$?
     if [ $rc -eq $OCF_SUCCESS ]; then
         ocf_exit_reason "garbd started outside of the cluster's control"
         return $OCF_ERR_GENERIC;
     fi
 
     touch $OCF_RESKEY_log
     chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log
     chmod 0640 $OCF_RESKEY_log
     [ -x /sbin/restorecon ] && /sbin/restorecon $OCF_RESKEY_log
 
     garbd_params="--address=${OCF_RESKEY_wsrep_cluster_address} \
                   --group ${OCF_RESKEY_wsrep_cluster_name} \
                   --log ${OCF_RESKEY_log}"
 
     if [ ! -z "${OCF_RESKEY_options}" ]; then
         garbd_params="${garbd_params} --options=${OCF_RESKEY_options}"
     fi
 
     # garbd has no parameter to run as a specific user,
     # so we need to start it by our own means
     pid=$(su - -s /bin/sh $OCF_RESKEY_user -c "${OCF_RESKEY_binary} ${garbd_params} >/dev/null 2>&1 & echo \$!")
 
     # garbd doesn't create a pidfile either, so we create our own
     echo $pid > $OCF_RESKEY_pid
     if [ $? -ne 0 ]; then
         ocf_exit_reason "Cannot create pidfile for garbd at $OCF_RESKEY_pid (rc=$?), please check your installation"
         return $OCF_ERR_GENERIC
     fi
 
     # Spin waiting for garbd to connect to the cluster.
     # Let the CRM/LRM time us out if required.
     start_wait=1
     while [ $start_wait -eq 1 ]; do
         garbd_monitor info
         rc=$?
         if [ $rc -eq $OCF_NOT_RUNNING ]; then
             ocf_exit_reason "garbd failed to start (pid=$pid), check logs in ${OCF_RESKEY_log}"
             return $OCF_ERR_GENERIC
         elif [ $rc -eq $OCF_SUCCESS ]; then
             start_wait=0
         fi
         sleep 2
     done
 
     ocf_log info "garbd connected to cluster \"${OCF_RESKEY_wsrep_cluster_name}\""
     return $OCF_SUCCESS
 }
 
 garbd_status()
 {
     local loglevel=$1
     local rc
     ocf_pidfile_status $OCF_RESKEY_pid
     rc=$?
 
     if [ $rc -eq 0 ]; then
         return $OCF_SUCCESS
     elif [ $rc -eq 2 ]; then
         return $OCF_NOT_RUNNING
     else
         # clean up if pidfile is stale
         if [ $rc -eq 1 ]; then
             ocf_log $loglevel "garbd not running: removing old PID file"
             rm -f $OCF_RESKEY_pid
         fi
         return $OCF_ERR_GENERIC
     fi
 }
 
+_port_by_pid()
+{
+    local pid
+    pid="$1"
+    if have_binary "netstat"; then
+        netstat -tnp 2>/dev/null | grep -s -q "ESTABLISHED.*${pid}/"
+    else
+        ss -Htnp 2>/dev/null | grep -s -q "^ESTAB.*pid=${pid}"
+    fi
+}
+
 garbd_monitor()
 {
     local rc
     local pid
     local loglevel=$1
 
     # Set loglevel to info during probe
     if ocf_is_probe; then
         loglevel="info"
     fi
 
     garbd_status $loglevel
     rc=$?
 
     # probe just wants to know if garbd is running or not
     if ocf_is_probe && [ $rc -ne $OCF_SUCCESS ]; then
         rc=$OCF_NOT_RUNNING
     fi
 
     # Consider garbd is working if it's connected to at least
     # one node in the galera cluster.
     # Note: a Galera node in Non-Primary state will be
     # stopped by the galera RA. So we can assume that
     # garbd will always be connected to the right partition
     if [ $rc -eq $OCF_SUCCESS ]; then
         pid=`cat $OCF_RESKEY_pid 2> /dev/null `
-        netstat -tnp 2>/dev/null | grep -s -q "ESTABLISHED.*${pid}/"
+        _port_by_pid $pid
         if [ $? -ne 0 ]; then
             ocf_log $loglevel "garbd disconnected from cluster \"${OCF_RESKEY_wsrep_cluster_name}\""
             rc=$OCF_ERR_GENERIC
         fi
     fi
 
     return $rc
 }
 
 garbd_stop()
 {
     local rc
     local pid
 
     if [ ! -f $OCF_RESKEY_pid ]; then
         ocf_log info "garbd is not running"
         return $OCF_SUCCESS
     fi
 
     pid=`cat $OCF_RESKEY_pid 2> /dev/null `
 
     ocf_log info "stopping garbd"
 
     # make sure the process is stopped
     ocf_stop_processes TERM 10 $pid
     rc=$?
 
     if [ $rc -ne 0 ]; then
         return $OCF_ERR_GENERIC
     else
         rm -f $OCF_RESKEY_pid
         ocf_log info "garbd stopped"
         return $OCF_SUCCESS
     fi
 }
 
 garbd_validate()
 {
     if ! have_binary "$OCF_RESKEY_binary"; then
         ocf_exit_reason "Setup problem: couldn't find command: $OCF_RESKEY_binary"
         return $OCF_ERR_INSTALLED;
     fi
 
     if ! have_binary "netstat"; then
-        ocf_exit_reason "Setup problem: couldn't find command: netstat"
-        return $OCF_ERR_INSTALLED;
+        if ! have_binary "ss"; then
+            ocf_exit_reason "Setup problem: couldn't find command: netstat or ss"
+            return $OCF_ERR_INSTALLED;
+        fi
     fi
 
     if [ -z "$OCF_RESKEY_wsrep_cluster_address" ]; then
         ocf_exit_reason "garbd must be configured with a wsrep_cluster_address value."
         return $OCF_ERR_CONFIGURED
     fi
 
     # unlike galera RA, ports must be set in cluster address for garbd
     # https://github.com/codership/galera/issues/98
     for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do
         echo $node | grep -s -q ':[1-9][0-9]*$'
         if [ $? -ne 0 ]; then
             ocf_exit_reason "wsrep_cluster_address must specify ports (gcomm://node1:port,node2:port)."
             return $OCF_ERR_CONFIGURED
         fi
     done
 
     # Ensure that the encryption method is set if garbd is configured
     # to use SSL.
     echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_(key|cert)='
     if [ $? -eq 0 ]; then
         echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_cipher='
         if [ $? -ne 0 ]; then
             ocf_exit_reason "option socket.ssl_cipher must be set if SSL is enabled."
             return $OCF_ERR_CONFIGURED
         fi
     fi
 
     if [ -z "$OCF_RESKEY_wsrep_cluster_name" ]; then
         ocf_exit_reason "garbd must be configured with a wsrep_cluster_name value."
         return $OCF_ERR_CONFIGURED
     fi
 
     if ! getent passwd $OCF_RESKEY_user >/dev/null 2>&1; then
         ocf_exit_reason "User $OCF_RESKEY_user doesn't exist"
         return $OCF_ERR_INSTALLED
     fi
 
     if ! getent group $OCF_RESKEY_group >/dev/null 2>&1; then
         ocf_exit_reason "Group $OCF_RESKEY_group doesn't exist"
         return $OCF_ERR_INSTALLED
     fi
 
     return $OCF_SUCCESS
 }
 
 case "$1" in
   meta-data)    meta_data
         exit $OCF_SUCCESS;;
   usage|help)   usage
         exit $OCF_SUCCESS;;
 esac
 
 garbd_validate
 rc=$?
 
 # trap configuration errors early, but don't block stop in such cases
 LSB_STATUS_STOPPED=3
 if [ $rc -ne 0 ]; then
     case "$1" in
         stop) exit $OCF_SUCCESS;;
         status) exit $LSB_STATUS_STOPPED;;
         *) exit $rc;;
     esac
 fi
 
 # What kind of method was invoked?
 case "$1" in
   start)    garbd_start;;
   stop)     garbd_stop;;
   status)   garbd_status err;;
   monitor)  garbd_monitor err;;
   promote)  garbd_promote;;
   demote)   garbd_demote;;
   validate-all) exit $OCF_SUCCESS;;
 
  *)     usage
         exit $OCF_ERR_UNIMPLEMENTED;;
 esac
diff --git a/heartbeat/portblock b/heartbeat/portblock
index c1a5759c6..cde10b940 100755
--- a/heartbeat/portblock
+++ b/heartbeat/portblock
@@ -1,566 +1,572 @@
 #!/bin/sh
 #
 # portblock: iptables temporary portblocking control 
 #
 # Author:	Sun Jiang Dong (initial version)
 #               Philipp Reisner (per-IP filtering)
 #
 # License:	GNU General Public License (GPL)
 #
 # Copyright:	(C) 2005 International Business Machines
 #
 #	  OCF parameters are as below:
 #		OCF_RESKEY_protocol
 #		OCF_RESKEY_portno
 #		OCF_RESKEY_action
 #		OCF_RESKEY_ip
 #		OCF_RESKEY_tickle_dir
 #		OCF_RESKEY_sync_script
 #######################################################################
 # Initialization:
 
 : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
 . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
 
 # Defaults
 OCF_RESKEY_ip_default="0.0.0.0/0"
 OCF_RESKEY_reset_local_on_unblock_stop_default="false"
 
 : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}}
 : ${OCF_RESKEY_reset_local_on_unblock_stop=${OCF_RESKEY_reset_local_on_unblock_stop_default}}
 #######################################################################
 CMD=`basename $0`
 TICKLETCP=$HA_BIN/tickle_tcp
 
 usage()
 {
 	cat <<END >&2
 	usage: $CMD {start|stop|status|monitor|meta-data|validate-all}
 
 	$CMD is used to temporarily block ports using iptables.
 
 	It can be used to blackhole a port before bringing
 	up an IP address, and enable it after a service is started.
 	To do that for samba, the following can be used:
 
 	crm configure <<EOF
 	primitive portblock-samba ocf:heartbeat:portblock \\
 	  params protocol=tcp portno=137,138 action=block
 	primitive portunblock-samba ocf:heartbeat:portblock \\
 	  params protocol=tcp portno=137,138 action=unblock
 	primitive samba-vip ocf:heartbeat:IPaddr2 \\
 	  params ip=10.10.10.20
 	group g-samba \\
 	  portblock-samba samba-vip nmbd smbd portunblock-samba
 	EOF
 
 	This will do the following things:
 
 	  - DROP all incoming packets for TCP ports 137 and 138
 	  - Bring up the IP alias 10.10.10.20
 	  - start the nmbd and smbd services
 	  - Re-enable TCP ports 137 and 138
 	        (enable normal firewall rules on those ports)
 
 	This prevents clients from getting TCP RST if they try to reconnect
 	to the service after the alias is enabled but before nmbd and smbd
 	are running.  These packets will cause some clients to give up
 	attempting to reconnect to the server.
 
 	Attempts to connect to UDP and other non-TCP ports which have nothing
 	listening can result in ICMP port unreachable responses, which can
 	have the same undesirable affect on some clients.
 
 	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 
 	fail-overed server.
 
 	Please note that this feature is often used for the floating IP fail-
 	over scenario where the long-lived TCP connections need to be tickled.
 	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 
 	action=unblock instance of the portblock resources.
 	For example, you may stack resources like below:
 		portblock action=block
 		services
 		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 
 	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 
 	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 
 	configure your /etc/csync2/csync2.cfg like:
 		group ticklegroup {
 		  host node1;
 		  host node2;
 		  key  /etc/csync2/ticklegroup.key;
 		  include /etc/csync2/csync2.cfg;
 		  include /tmp/tickle;
 		  auto younger;
 		}
 	Then specify the parameter sync_script as "csync2 -xv".
 
 END
 }
 
 meta_data() {
 	cat <<END
 <?xml version="1.0"?>
 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
 <resource-agent name="portblock">
 <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.
 Note that the tickle ACK function is new as of version 3.0.2 and
 hasn't yet seen widespread use.
 </longdesc>
 <shortdesc lang="en">Block and unblocks access to TCP and UDP ports</shortdesc>
 
 <parameters>
 <parameter name="protocol" unique="0" required="1">
 <longdesc lang="en">
 The protocol used to be blocked/unblocked.
 </longdesc>
 <shortdesc lang="en">protocol</shortdesc>
 <content type="string" default="" />
 </parameter>
 
 <parameter name="portno" unique="0" required="1">
 <longdesc lang="en">
 The port number used to be blocked/unblocked.
 </longdesc>
 <shortdesc lang="en">portno</shortdesc>
 <content type="string" default="" />
 </parameter>
 
 <parameter name="action" unique="0" required="1">
 <longdesc lang="en">
 The action (block/unblock) to be done on the protocol::portno.
 </longdesc>
 <shortdesc lang="en">action</shortdesc>
 <content type="string" default="" />
 </parameter>
 
 <parameter name="reset_local_on_unblock_stop" unique="0" required="0">
 <longdesc lang="en">
 If for some reason the long lived server side TCP sessions won't be cleaned up
 by a reconfiguration/flush/stop of whatever services this portblock protects,
 they would linger in the connection table, even after the IP is gone
 and services have been switched over to another node.
 
 An example would be the default NFS kernel server.
 
 These "known" connections may seriously confuse and delay a later switchback.
 
 Enabling this option will cause this agent to try to get rid of these connections
 by injecting a temporary iptables rule to TCP-reset outgoing packets from the
 blocked ports, and additionally tickle them locally,
 just before it starts to DROP incoming packets on "unblock stop".
 </longdesc>
 <shortdesc lang="en">(try to) reset server TCP sessions when unblock stops</shortdesc>
 <content type="boolean" default="${OCF_RESKEY_reset_local_on_unblock_stop_default}" />
 </parameter>
 
 <parameter name="ip" unique="0" required="0">
 <longdesc lang="en">
 The IP address used to be blocked/unblocked.
 </longdesc>
 <shortdesc lang="en">ip</shortdesc>
 <content type="string" default="${OCF_RESKEY_ip_default}" />
 </parameter>
 
 <parameter name="tickle_dir" unique="0" required="0">
 <longdesc lang="en">
 The shared or local directory (_must_ be absolute path) which 
 stores the established TCP connections.
 </longdesc>
 <shortdesc lang="en">Tickle directory</shortdesc>
 <content type="string" default="" />
 </parameter>
 
 <parameter name="sync_script" unique="0" required="0">
 <longdesc lang="en">
 If the tickle_dir is a local directory, then the TCP connection state
 file has to be replicated to other nodes in the cluster. It can be
 csync2 (default), some wrapper of rsync, or whatever. It takes the
 file name as a single argument. For csync2, set it to "csync2 -xv".
 </longdesc>
 <shortdesc lang="en">Connection state file synchronization script</shortdesc>
 <content type="string" default="" />
 </parameter>
 </parameters>
 
 <actions>
 <action name="start" timeout="20s" />
 <action name="stop" timeout="20s" />
 <action name="status" depth="0" timeout="10s" interval="10s" />
 <action name="monitor" depth="0" timeout="10s" interval="10s" />
 <action name="meta-data" timeout="5s" />
 <action name="validate-all" timeout="5s" />
 </actions>
 </resource-agent>
 END
 }
 
 
 #
 #	Because this is the normal usage, we consider "block"
 #	resources to be pseudo-resources -- that is, their status can't
 #	be reliably determined through external means.
 #	This is because we expect an "unblock" resource to come along
 #	and disable us -- but we're still in some sense active...
 #
 
 #active_grep_pat {udp|tcp} portno,portno
 active_grep_pat()
 {
   w="[ 	][ 	]*"
   any="0\\.0\\.0\\.0/0"
   echo "^DROP${w}${1}${w}--${w}${any}${w}${3}${w}multiport${w}dports${w}${2}\>"
 }
 
 #chain_isactive  {udp|tcp} portno,portno ip
 chain_isactive()
 {
   PAT=`active_grep_pat "$1" "$2" "$3"`
   $IPTABLES $wait -n -L INPUT | grep "$PAT" >/dev/null
 }
 
 save_tcp_connections()
 {
 	[ -z "$OCF_RESKEY_tickle_dir" ] && return
 	statefile=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip
 	if [ -z "$OCF_RESKEY_sync_script" ]; then
 		netstat -tn |awk -F '[:[:space:]]+' '
 			$8 == "ESTABLISHED" && $4 == "'$OCF_RESKEY_ip'" \
 			{printf "%s:%s\t%s:%s\n", $4,$5, $6,$7}' |
 			dd of="$statefile".new conv=fsync status=none &&
 			mv "$statefile".new "$statefile"
 	else
 		netstat -tn |awk -F '[:[:space:]]+' '
 			$8 == "ESTABLISHED" && $4 == "'$OCF_RESKEY_ip'" \
 			{printf "%s:%s\t%s:%s\n", $4,$5, $6,$7}' \
 			> $statefile
 		$OCF_RESKEY_sync_script $statefile > /dev/null 2>&1 &
 	fi
 }
 
 tickle_remote()
 {
 	[ -z "$OCF_RESKEY_tickle_dir" ] && return
 	echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
 	f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip
 	[ -r $f ] || return
 	$TICKLETCP -n 3 < $f
 }
 
 tickle_local()
 {
 	[ -z "$OCF_RESKEY_tickle_dir" ] && return
 	f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip
 	[ -r $f ] || return
+
+	checkcmd="netstat -tn"
+	if ! have_binary "netstat"; then
+		checkcmd="ss -Htn"
+	fi
+
 	# swap "local" and "remote" address,
 	# so we tickle ourselves.
 	# We set up a REJECT with tcp-reset before we do so, so we get rid of
 	# the no longer wanted potentially long lived "ESTABLISHED" connection
 	# entries on the IP we are going to delet in a sec.  These would get in
 	# the way if we switch-over and then switch-back in quick succession.
 	local i
 	awk '{ print $2, $1; }' $f | $TICKLETCP
-	netstat -tn | grep -Fw $OCF_RESKEY_ip || return
+	$checkcmd | grep -Fw $OCF_RESKEY_ip || return
 	for i in 0.1 0.5 1 2 4 ; do
 		sleep $i
 		awk '{ print $2, $1; }' $f | $TICKLETCP
-		netstat -tn | grep -Fw $OCF_RESKEY_ip || break
+		$checkcmd | grep -Fw $OCF_RESKEY_ip || break
 	done
 }
 
 SayActive()
 {
   echo "$CMD DROP rule for INPUT chain [$*]  is running (OK)"
 }
 
 SayConsideredActive()
 {
   echo "$CMD DROP rule for INPUT chain [$*] considered to be running (OK)"
 }
 
 SayInactive()
 {
   echo "$CMD DROP rule for INPUT chain [$*] is inactive"
 }
 
 #IptablesStatus  {udp|tcp} portno,portno ip {block|unblock}
 IptablesStatus() {
     local rc
     rc=$OCF_ERR_GENERIC
     activewords="$CMD $1 $2 is running (OK)"
     if chain_isactive "$1" "$2" "$3"; then
 	case $4 in
 	    block)	
 		SayActive $*
 		rc=$OCF_SUCCESS
 		;;
 	    *)
  		SayInactive $*
 		rc=$OCF_NOT_RUNNING
 		;;
 	esac
     else
 	case $4 in
 	    block)
 		if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then
 		    SayConsideredActive $*
 		    rc=$OCF_SUCCESS
 		else
 		    SayInactive $*
 		    rc=$OCF_NOT_RUNNING
 		fi
 		;;
 	    
 	    *)
 		if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then
 			SayActive $*
 			#This is only run on real monitor events.
 			save_tcp_connections
 			rc=$OCF_SUCCESS
 		else
 			SayInactive $*
 			rc=$OCF_NOT_RUNNING
 		fi
 		;;
 	esac
     fi      
     
     return $rc
 }
 
 #IptablesBLOCK  {udp|tcp} portno,portno ip
 IptablesBLOCK()
 {
   local rc=0
   local try_reset=false
   if	[ "$1/$4/$__OCF_ACTION" = tcp/unblock/stop ] &&
 	ocf_is_true $reset_local_on_unblock_stop
   then
 	try_reset=true
   fi
   if
     chain_isactive "$1" "$2" "$3"
   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=$?
     if $try_reset ; then
       $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset
     fi
   fi
 
   return $rc
 }
 
 #IptablesUNBLOCK  {udp|tcp} portno,portno ip
 IptablesUNBLOCK()
 {
   if
     chain_isactive "$1" "$2" "$3"
   then
     $IPTABLES $wait -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP
   else
     : Chain Not active
   fi
 
   return $?
 }
 
 #IptablesStart  {udp|tcp} portno,portno ip {block|unblock}
 IptablesStart()
 {
   ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start
   case $4 in
     block)	IptablesBLOCK "$@";;
     unblock)
 		IptablesUNBLOCK "$@"
 		rc=$?
 		tickle_remote
 		#ignore run_tickle_tcp exit code!
 		return $rc
 		;;
     *)		usage; return 1;
   esac
 
   return $?
 }
 
 #IptablesStop  {udp|tcp} portno,portno ip {block|unblock}
 IptablesStop()
 {
   ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop
   case $4 in
     block)	IptablesUNBLOCK "$@";;
     unblock)
 		save_tcp_connections
 		IptablesBLOCK "$@"
 		;;
     *)		usage; return 1;;
   esac
 
   return $?
 }
 
 #
 #	Check if the port is valid, this function code is not decent, but works
 #
 CheckPort() {
 #	Examples of valid port: "1080", "1", "0080"
 #	Examples of invalid port: "1080bad", "0", "0000", ""
   echo $1 |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
 }
 
 IptablesValidateAll()
 {
   check_binary $IPTABLES
   case $protocol in
     tcp|udp)
 	;;
     *)
 	ocf_log err "Invalid protocol $protocol!"
 	exit $OCF_ERR_CONFIGURED
 	;;
   esac
 
   if CheckPort "$portno"; then
 	:
   else
 	ocf_log err "Invalid port number $portno!"
 	exit $OCF_ERR_CONFIGURED
   fi
 
   if [ -n "$OCF_RESKEY_tickle_dir" ]; then
 	if [ x"$action" != x"unblock" ]; then
 		ocf_log err "Tickles are only useful with action=unblock!"
 		exit $OCF_ERR_CONFIGURED
 	fi
 	if [ ! -d "$OCF_RESKEY_tickle_dir" ]; then
 		ocf_log err "The tickle dir doesn't exist!"
 		exit $OCF_ERR_INSTALLED	  	
 	fi
   fi
 
   case $action in
     block|unblock)	
 	;;
     *)		
 	ocf_log err "Invalid action $action!"
 	exit $OCF_ERR_CONFIGURED
 	;; 
   esac
 
   if ocf_is_true $reset_local_on_unblock_stop; then
 	if [ $action != unblock ] ; then
 		ocf_log err "reset_local_on_unblock_stop is only relevant with action=unblock"
 		exit $OCF_ERR_CONFIGURED
 	fi
 	if [ -z $OCF_RESKEY_tickle_dir ] ; then
 		ocf_log warn "reset_local_on_unblock_stop works best with tickle_dir enabled as well"
 	fi
   fi
 
   return $OCF_SUCCESS
 }
 
 if
   ( [ $# -ne 1 ] )
 then
   usage
   exit $OCF_ERR_ARGS
 fi
 
 case $1 in
   meta-data)		meta_data
 			exit $OCF_SUCCESS
 			;;
 
   usage)		usage
 			exit $OCF_SUCCESS
 			;;
   *)			;;
 esac
 
 if [ -z "$OCF_RESKEY_protocol" ]; then
   ocf_log err "Please set OCF_RESKEY_protocol"
   exit $OCF_ERR_CONFIGURED
 fi 
 
 if [ -z "$OCF_RESKEY_portno" ]; then
   ocf_log err "Please set OCF_RESKEY_portno"
   exit $OCF_ERR_CONFIGURED
 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 | awk -F ' v' '{print $NF}')
 ocf_version_cmp "$version" "1.4.19.1"
 if [ "$?" -eq "2" ]; then
     wait="-w"
 else
     wait=""
 fi
 
 protocol=$OCF_RESKEY_protocol
 portno=$OCF_RESKEY_portno
 action=$OCF_RESKEY_action
 ip=$OCF_RESKEY_ip
 reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop
 
 case $1 in
   start)	
 			IptablesStart $protocol $portno $ip $action 
 			;;
 
   stop)		
 			IptablesStop $protocol $portno $ip $action
 			;;
 
   status|monitor)	
 			IptablesStatus $protocol $portno $ip $action
 			;;
 
   validate-all)
 			IptablesValidateAll
 			;;
 
   *)			usage
 			exit $OCF_ERR_UNIMPLEMENTED
 			;;
 esac
 
 exit $?