Client component: callhome.sh

#!/bin/sh -e

export PATH="/usr/local/bin:/usr/bin:/bin"

config="${HOME}/.ssh/callhome.config"
key="${HOME}/.ssh/callhome.key"
lock="${HOME}/.ssh/callhome.pid"
local_port="22222"
timeout="60"

ssh_config() {
  cat <<EOCF
# No Agent or X11 forwards needed
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no

# Timeout after a sensible amount of time
# Hosts with volatile uplinks need this to know when to relink
ConnectTimeout 30
ServerAliveInterval 20
ServerAliveCountMax 3

# This profile is used to transmit the newly generated key and port config
Host callhome-setup
  HostName alba.cyberleo.net
  Port 22
  User cyberleo

# This profile is used to connect
Host callhome
  HostName alba.cyberleo.net
  Port 22
  User callhome
  IdentityFile ${key}
  # Do not use SSH-Agent identities
  IdentitiesOnly yes
  # Do not prompt for passwords
  PreferredAuthentications publickey
EOCF
}

setup_config() {
  mkdir -p "$(dirname "${config}")"
  ssh_config > "${config}"
}

callhome_ssh() {
  ssh -F "${config}" "${@}"
}

setup_key() {
  echo "Generating remote-access SSH key..." >&2
  mkdir -p "$(dirname "${key}")"
  ssh-keygen -q -b 3072 -P "" -f "${key}"
  echo "" >&2
  echo "Transmitting public key; please log in." >&2
  echo "" >&2
  callhome_ssh callhome-setup "/bin/mkdir -p ~/.ssh && /bin/cat >> ~/.ssh/pending_authorized_keys" < "${key}.pub" || {
    echo "Key transmission failed. Check for any errors and correct them, then try again." >&2
    echo "----8<----" >&2
    cat "${key}.pub"
    echo "----8<----" >&2
    return 1
  }
  echo "Key transmitted. You can configure this key on the server now." >&2
  return 0
}

regexpize_allowed_symbols() {
  echo "${*}" | sed -Ee '
    s/^[[:space:]]*/^\\(/;
    s/[[:space:]]*$/\\):/;
    s/[[:space:]]+/\\|/g;
    s/$/ /
  '
}

remote_config() {
  allowed_symbols="ident port"
  allowed_symbols_regexp="$(regexpize_allowed_symbols "${allowed_symbols}")"
  while ! callhome_ssh callhome config
  do
    sleep 1
  done | while read line
  do
    echo "${line}" | grep "${allowed_symbols_regexp}" || echo "Ignoring invalid config line: ${line}" >&2
  done | sed -e "s/: /='/; s/$/'/"
}

remote_kill() {
  callhome_ssh callhome kill
}

remote_loop() {
  callhome_ssh -fn -o ExitOnForwardFailure=yes -L${local_port}:127.0.0.1:${port} -R${port}:127.0.0.1:22 callhome loop
}

case "$(uname -s)" in
FreeBSD)
# FreeBSD version
ssh_pid() {
  sockstat -P tcp -lp "${local_port}" | tail -n +2 | while read user command pid fd proto local foreign
  do
    [ "${user}" = "${USER}" -a "${command}" = "ssh" ] || continue
    echo "${pid}"
  done | sort -u
}
  ;;
Linux)
# Linux version
ssh_pid() {
  netstat --numeric-hosts --numeric-ports -eplt 2>&- | awk 'BEGIN{out=""}{if(out){print}}/^Proto/{out="yes"}' | while read proto recvq sendq local foreign state user inode pidcmd
  do
    pid="${pidcmd%%/*}"
    command="${pidcmd##*/}"
    [ "${user}" = "${USER}" -a "${command}" = "ssh" ] || continue
    echo "${pid}"
  done | sort -u
}
  ;;
Darwin)
# Darwin version
ssh_pid() {
  me=$(id -u)
  /usr/sbin/lsof -i -l -n -P | grep '(LISTEN)' | grep " ${me} " | grep 'ssh' | grep ":${local_port} " | while read command pid user fd type device size node name state
  do
    [ "${user}" = "${me}" -a "${command}" = "ssh" ] || continue
    echo "${pid}"
  done | sort -u
}
  ;;
*) echo "Unsupported OStype $(uname -s)" >&2; exit 1 ;;
esac

ssh_up() {
  [ "$(ssh_pid)" ]
}

local_kill() {
  pids="$(ssh_pid)"
  [ -z "${pids}" ] || kill -TERM ${pids}
}

checkup() {
  nc -w 20 127.0.0.1 "${local_port}" < /dev/null | grep -q ^SSH
}

terminate_cleanup() {
  trap - EXIT HUP INT TERM KILL
  local_kill
}

trap "terminate_cleanup" EXIT HUP INT TERM KILL

[ -f "${config}" -a -s "${config}" ] || setup_config
[ -f "${key}" ] || { setup_key; exit; }

eval $(remote_config)
[ "${ident}" -a "${port}" ] || {
  echo "Configuration download failed" >&2
  exit 1
}

printf "Calling home: I am %s (port %s)\n" "${ident}" "${port}"

while true
do
  # Avoid looping more than once per second during quick failures
  [ "$(date +%s)" -ne "${lastloop:-0}" ] || sleep 1
  lastloop="$(date +%s)"

  # Busy loop as long as everything is working
  # Check that ssh is running every 20 seconds
  # Poke the port every 60 seconds
  while checkup
  do
    for iter in 1 2 3
    do
      ssh_up || break
      sleep 20
    done
  done

  # If it's not working, try and make it work
  # Kill any local processes
  local_kill || true
  # Attempt to establish connection
  if ! remote_loop
  then
    # If it doesn't work, try to kill remote and fall through for another loop
    remote_kill || true
  fi
done

Systemd callhome.service

[Unit]
Description = CallHome script
Requires = network.target

[Service]
Type = simple
Environment=HOME=/root
ExecStart = /root/bin/callhome
Restart = always
RestartSec = 5s

[Install]
WantedBy = multi-user.target

This bit is FreeBSD-specific; but you can port it in much the same way as callhome.sh (see ssh_pid() ).
Server component: force_cmd

#!/bin/sh -e

# Read in config
ident="${1}"
port="${2}"

kill_current_mapping_for_port() {
  local port="${1}"
  sockstat -P tcp -lp "${port}" | tail -n +2 | while read user command pid fd proto local foreign
  do
    [ "${user}" = "${USER}" -a "${command}" = "sshd" ] || continue
    kill -TERM "${pid}"
    echo "Killed ${pid}: ${command}" >&2
  done
}

logit() {
  echo "$(date): ${*}" >> "${HOME}/callhome.log"
}

logit "${ident}:${port} requested '${SSH_ORIGINAL_COMMAND}' from ${SSH_CLIENT}"

case "$SSH_ORIGINAL_COMMAND" in
config)
  echo "ident: ${ident}"
  echo "port: ${port}"
  ;;
loop)
  echo "Keepalive loop started; break to terminate."
  exec sh -ec 'while sleep 300; do printf "."; done'" # ${ident} ${port}"
  ;;
kill)
  kill_current_mapping_for_port "${port}"
  ;;
ping)
  echo "pong"
  ;;
*)
  echo "Rejected"
  exit 1
  ;;
esac

Place name and port number into force command to configure the client. Give each client its own distinct name and port number. Sample authorized_keys entry:

command="/usr/home/callhome/.ssh/force_cmd phoenix 22004" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJDg49aa0ObN2Xmi2CxkQO9bKNu6SR+n0zzbnl+6CayqIdsBhm56RVnOPr3bAAMj+36ygdjqp2CEeGS4g0S5B9FcGZkrWxyy9t/ixhOWo2qB+Yx55M0C8uB0ie1aN7UV+k8nBy8ahxQ7NVQ6uPdJ8F/XlhuYPMkJtuLGDv/GjDWhAvv11J2Ff9p3Wl1AIVkyvvIil9BaBBg+XmnwQAAdKf5rb7+ouG4tnQ3Mo2OEkj61B10vvDQNAD1VqGAm+xskjNyoM4ETS3ehA/j4yPaF+vr6fcLL2UhA2MJm3Y8QP3xq1JzTEnmBrJM0pxBsy0NvsKchSyyH3GmgzaB/rxn6uAnQn87nZXoL1V7wghr0HylA/Dj5xq+34zcnv8osmz7B63xFujRxZuxSFjcHr4k+PUx4vjhvIDT9oXeckif71QfTulsBxnMyL2W7alY2eku00ATLOhr+QBIeURzrCSYSXgEm5CRFJ/9T7EDYJPwx2MeD8NRKgdjTiWbLaPYylLLD0= cyberleo@phoenix-lan

PHP Warning

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead:"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"

Warning: "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead:"