{
_ip="$1"
- netstat -tn | awk -v ip=$_ip \
- 'index($1, "tcp") == 1 && \
- (index($4, ip ":") == 1 || index($4, "::ffff:" ip ":") == 1) \
- && $6 == "ESTABLISHED" \
- {print $4" "$5}'
+ ss -tn state established "src [$_ip]" | awk 'NR > 1 {print $3, $4}'
}
########################################################
# What public IPs do I hold?
_ips=$(ctdb -X ip | awk -F'|' -v pnn=$pnn '$3 == pnn {print $2}')
- # IPs as a regexp choice
- _ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))"
+ # IPs and port as ss filters
+ _ip_filter=""
+ for _ip in $_ips ; do
+ _ip_filter="${_ip_filter}${_ip_filter:+ || }src [${_ip}]"
+ done
+ _port_filter="sport == :${_port}"
# Record connections to our public IPs in a temporary file.
# This temporary file is in CTDB's private state directory and
# $$ is used to avoid a very rare race involving CTDB's script
# debugging. No security issue, nothing to see here...
_my_connections="${tickledir}/${_port}.connections.$$"
- netstat -tn |
- awk -v destpat="^${_ipschoice}:${_port}\$" \
- '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' |
+ # Parentheses are needed around the filters for precedence but
+ # the parentheses can't be empty!
+ ss -tn state established \
+ "${_ip_filter:+( ${_ip_filter} )}" \
+ "${_port_filter:+( ${_port_filter} )}" |
+ awk 'NR > 1 {print $4, $3}' |
sort >"$_my_connections"
# Record our current tickles in a temporary file
--- /dev/null
+#!/bin/bash
+
+prog="ss"
+
+usage ()
+{
+ cat >&2 <<EOF
+Usage: $prog -tn state established [ '(' ip-filter ')' ] [ '(' port-filter ')' ]
+
+A fake ss stub that prints items depending on the variables
+FAKE_NETSTAT_TCP_ESTABLISHED and FAKE_NETSTAT_TCP_ESTABLISHED_FILE.
+
+Note that "-tn state established" must be given.
+
+EOF
+ exit 1
+}
+
+if [ "$1" != "-tn" -o "$2" != "state" -o "$3" != "established" ] ; then
+ usage
+fi
+
+shift 3
+
+# Check if socket has matches in both ok_ips and ok_ports
+filter_socket ()
+{
+ ok_ips="$1"
+ ok_ports="$2"
+ socket="$3"
+
+ ip="${socket%:*}"
+ port="${socket##*:}"
+
+ if [ "$ok_ports" != "|" -a "${ok_ports#*|${port}|}" = "$ok_ports" ] ; then
+ return 1
+ fi
+ if [ "$ok_ips" != "|" -a "${ok_ips#*|${ip}|}" = "$ok_ips" ] ; then
+ return 1
+ fi
+
+ return 0
+}
+
+ss_tcp_established ()
+{
+ echo "Recv-Q Send-Q Local Address:Port Peer Address:Port"
+
+ # Very limited implementation:
+ # We only expect to find || inside parentheses
+ # We don't expect to see && - it is implied by juxtaposition
+ # Operator for port comparison is ignored and assumed to be ==
+
+ # Build lists of source ports and source IP addresses where each
+ # entry is surrounded by '|' characters. These lists can be
+ # easily "searched" using the POSIX prefix and suffix removal
+ # operators.
+ in_parens=false
+ sports="|"
+ srcs="|"
+
+ while [ -n "$1" ] ; do
+ case "$1" in
+ \() in_parens=true ; shift ;;
+ \)) in_parens=false ; shift ;;
+ \|\|) if ! $in_parens ; then usage ; fi ; shift ;;
+ sport) p="${3#:}" ; sports="${sports}${p}|" ; shift 3 ;;
+ src) ip="${2#\[}" ; ip="${ip%\]}" ; srcs="${srcs}${ip}|" ; shift 2 ;;
+ *) usage ;;
+ esac
+ done
+
+ for i in $FAKE_NETSTAT_TCP_ESTABLISHED ; do
+ src="${i%|*}"
+ dst="${i#*|}"
+ if filter_socket "$srcs" "$sports" "$src" ; then
+ echo 0 0 "$src" "$dst"
+ fi
+ done
+ while read src dst ; do
+ if filter_socket "$srcs" "$sports" "$src" ; then
+ echo 0 0 "$src" "$dst"
+ fi
+ done <"$FAKE_NETSTAT_TCP_ESTABLISHED_FILE"
+}
+
+# Yes, lose the quoting so we can do a hacky parsing job
+ss_tcp_established $*