[PATCH 1/2] Add test to check that session multiplexing (with, ControlMaster=auto) works fine for concurrent ssh connections

Jens Rosenboom Jens.Rosenboom at web.de
Tue Sep 15 21:27:04 AEST 2026


This is a new test that checks if ControlMaster=auto works fine for 
multiple ssh connections that are started at the same time.
Signed-off-by: Jens Rosenboom <jens.rosenboom at web.de>

---
  regress/multiplex.sh   | 46 ++++++++++++++++++++++++++++++++++++
  regress/reconfigure.sh |  2 ++
  regress/test-exec.sh   | 53 ++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 101 insertions(+)

diff --git a/regress/multiplex.sh b/regress/multiplex.sh
index 584bbbe22..239346863 100644
--- a/regress/multiplex.sh
+++ b/regress/multiplex.sh
@@ -245,3 +245,49 @@ wait $SSH_PID
  kill -0 $SSH_PID >/dev/null 2>&1 && fatal "stop command failed"
  SSH_PID="" # Already gone, so don't kill in cleanup

+# test that, when no master is initially available, multiple concurrent 
ssh connections actually go over a single mux master socket
+verbose "test $tid: concurrent connections over a single control socket 
(with ControlMaster=auto)"
+test ! -e "$CTL" || fail "control socket still exists"
+barrier="${SSH_REGRESS_TMP}/mux-barrier"
+rm -f "$barrier"
+mkfifo "$barrier"
+pids=""
+if [ -n "$SUDO" ]; then
+    TC=$(command -v tc)
+fi
+if [ -n "$TC" ]; then
+    $SUDO $TC qdisc replace dev lo root netem delay 500ms
+else
+    verbose "SUDO or tc(8) not available, running without induced 
network delay"
+fi
+
+i=0
+while [ $i -lt 10 ]; do
+    (
+        # opening the fifo for reading waits for a writing end to open
+        exec 3< "$barrier"
+        exec ${SSH} -F$OBJ/ssh_config -o ControlMaster=auto -S$CTL 
otherhost "sleep 4" \
+            >>$TEST_REGRESS_LOGFILE 2>&1
+    ) &
+    pids="$pids $!"
+    i=$((i + 1))
+done
+
+# wait a moment for the sub-shells to have started
+sleep 1
+
+# release all 10 clients (by opening the fifo for writing; it is closed 
again, immediately)
+: > "$barrier"
+
+sleep 2
+count_connection_sockets
+connections=$?
+if [ -n "$TC" ]; then
+    $SUDO $TC qdisc del dev lo root
+fi
+[ "$connections" -eq 1 ] || fail "concurrent connections over a single 
control socket (with ControlMaster=auto) failed, $connections sockets 
were used"
+ret=0
+for pid in $pids; do
+    wait "$pid" || ret=1
+done
+[ "$ret" -eq 0 ] || fail "concurrent connections over a single control 
socket (with ControlMaster=auto) failed"
diff --git a/regress/reconfigure.sh b/regress/reconfigure.sh
index d5b4e9808..d96ad9405 100644
--- a/regress/reconfigure.sh
+++ b/regress/reconfigure.sh
@@ -45,6 +45,8 @@ fi
  trace "reconfigure with active clients"
  ${SSH} -F $OBJ/ssh_config somehost sleep 10  # authenticated client
  ${NC} -d 127.0.0.1 $PORT >/dev/null &  # unauthenticated client
+NC_PID=$!
+trap 'kill "$NC_PID" 2>/dev/null' EXIT
  PID=`$SUDO cat $PIDFILE`
  rm -f $PIDFILE
  $SUDO kill -HUP $PID
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index 30a2a28ab..2e56887a4 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -474,6 +474,59 @@ make_tmpdir ()
      SSH_REGRESS_TMP="$($OBJ/mkdtemp openssh-XXXXXXXX)" || \
          fatal "failed to create temporary directory"
  }
+
+count_connection_sockets ()
+{
+    [ -z "$PIDFILE" ] && return
+    [ -f "$PIDFILE" ] || return
+    pid=`$SUDO cat $PIDFILE`
+    if [ "X$pid" = "X" ]; then
+        echo "no sshd running" 1>&2
+        return
+    elif [ $pid -lt 2 ]; then
+        echo "bad pid for sshd: $pid" 1>&2
+        return
+    fi
+
+    sockets=""
+    case "$(uname)" in
+    Linux)
+        if have_prog ss; then
+            sockets=$($SUDO ss -Htn state established \
+                "( dport = :$PORT )")
+        elif have_prog netstat; then
+            sockets=$($SUDO netstat -tn 2>/dev/null | \
+                awk -v p=":$PORT" '$4 ~ p"$" && $6=="ESTABLISHED"')
+        else
+            skip "count_connection_sockets: no ss(8) or netstat(8)"
+        fi
+        ;;
+    Darwin|FreeBSD|NetBSD|DragonFly)
+        have_prog netstat || \
+            skip "count_connection_sockets: no netstat(8)"
+        sockets=$($SUDO netstat -an -p tcp 2>/dev/null | \
+            awk -v p=".$PORT" '$4 ~ p"$" && $6=="ESTABLISHED"')
+        ;;
+    OpenBSD)
+        have_prog netstat || \
+            skip "count_connection_sockets: no netstat(8)"
+        sockets=$($SUDO netstat -an -f inet 2>/dev/null | \
+            awk -v p=".$PORT" \
+            '$1=="tcp" && $4 ~ p"$" && $6=="ESTABLISHED"')
+        ;;
+    SunOS)
+        have_prog netstat || \
+            skip "count_connection_sockets: no netstat(8)"
+        sockets=$($SUDO netstat -an -f inet -P tcp 2>/dev/null | \
+            awk -v p="\\.$PORT\$" '$1 ~ p && $6 ~ /ESTABLISHED/')
+        ;;
+    *)
+        skip "count_connection_sockets: unsupported OS $(uname)"
+        ;;
+    esac
+
+    return $(echo "$sockets" | grep -c .)
+}
  # End of portable specific functions

  stop_sshd ()
-- 
2.55.0




More information about the openssh-unix-dev mailing list