]> git.corax.cc Git - toolbox/commitdiff
utils/ipc-sshtunnel: Add script for establishing IPC-over-SSH tunnels
authorMatthias Kruk <m@m10k.eu>
Sat, 8 Oct 2022 04:41:40 +0000 (13:41 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 8 Oct 2022 04:50:53 +0000 (13:50 +0900)
This commit adds ipc-sshtunnel, a utility script for establishing a
bi-directional tunnel for IPC PubSub messages over SSH. This allows
scripts on separate machines to communicate even without a shared
file system.

Makefile
utils/ipc-sshtunnel.sh [new file with mode: 0755]

index e84b6548fd42ca628b5d9d933224281466062712..9d7dabeb7605ffe6af1f3193bf2fdf9172cece45 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -25,11 +25,13 @@ install:
        ln -sf $(PREFIX)/share/toolbox/toolbox.sh $(DESTDIR)/$(PREFIX)/bin/toolbox.sh
        ln -sf $(PREFIX)/share/toolbox/utils/ipc-tap.sh $(DESTDIR)/$(PREFIX)/bin/ipc-tap
        ln -sf $(PREFIX)/share/toolbox/utils/ipc-inject.sh $(DESTDIR)/$(PREFIX)/bin/ipc-inject
+       ln -sf $(PREFIX)/share/toolbox/utils/ipc-sshtunnel.sh $(DESTDIR)/$(PREFIX)/bin/ipc-sshtunnel
 
 uninstall:
        rm $(DESTDIR)/$(PREFIX)/bin/toolbox.sh
        rm $(DESTDIR)/$(PREFIX)/bin/ipc-tap
        rm $(DESTDIR)/$(PREFIX)/bin/ipc-inject
+       rm $(DESTDIR)/$(PREFIX)/bin/ipc-sshtunnel
        rm -rf $(DESTDIR)/$(PREFIX)/share/toolbox
 
 .PHONY: $(PHONY)
diff --git a/utils/ipc-sshtunnel.sh b/utils/ipc-sshtunnel.sh
new file mode 100755 (executable)
index 0000000..2c28c2b
--- /dev/null
@@ -0,0 +1,143 @@
+#!/bin/bash
+
+# ipc-sshtunnel.sh - Tunnel toolbox PubSub IPC messages over SSH
+# Copyright (C) 2022 Matthias Kruk
+#
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+_topic_add() {
+       local name="$1"
+       local value="$2"
+
+       declare -A map
+
+       # input_topics is inherited from main() via opt_parse()
+       # output_topics is inherited from main() via opt_parse()
+       map["input-topic"]=input_topics
+       map["output-topic"]=output_topics
+
+       if array_contains "$name" "${!map[@]}"; then
+               declare -n topic_array="${map[$name]}"
+               topic_array+=("$value")
+       else
+               log_error "Invalid option name: $name"
+               return 1
+       fi
+
+       return 0
+}
+
+local_to_remote() {
+       local remote="$1"
+       local endpoint="$2"
+       local topics=("${@:3}")
+
+       local topic
+       local args
+
+       args=()
+
+       for topic in "${topics[@]}"; do
+               args+=(--topic "$topic")
+       done
+
+       ( ipc-tap "${args[@]}" | ssh "$remote" ipc-inject ) &
+       echo "$!"
+       return 0
+}
+
+remote_to_local() {
+       local remote="$1"
+       local endpoint="$2"
+       local topics=("${@:3}")
+
+       local topic
+       local args
+
+       for topic in "${topics[@]}"; do
+               args+=(--topic "$topic")
+       done
+
+       ( ssh -n "$remote" ipc-tap "${args[@]}" | ipc-inject ) &
+       echo "$!"
+       return 0
+}
+
+process_is_running() {
+       local -i pid="$1"
+
+       kill -0 "$pid" &>/dev/null
+       return "$?"
+}
+
+spawn_tunnel() {
+       local tunnel_func="$1"
+       local remote="$2"
+       local topics=("${@:3}")
+
+       local -i tunnel
+
+       if tunnel=$("$tunnel_func" "$remote" "$endpoint" "${topics[@]}"); then
+               while inst_running && process_is_running "$tunnel"; do
+                       sleep 5
+               done
+
+               kill "$tunnel" &>/dev/null
+       else
+               return 1
+       fi
+
+       return 0
+}
+
+main() {
+       local input_topics
+       local output_topics
+       local remote
+
+       input_topics=()
+        output_topics=()
+
+       opt_add_arg "i" "input-topic"  "v"  "" "Topic to relay from the remote side (may be used more than once)" \
+                   "" _topic_add
+       opt_add_arg "o" "output-topic" "v"  "" "Topic to relay to the remote side (may be used more than once)"   \
+                   "" _topic_add
+       opt_add_arg "r" "remote"       "rv" "" "Address of the remote side"
+
+       if ! opt_parse "$@"; then
+               return 1
+       fi
+
+       remote=$(opt_get "remote")
+
+       if ! inst_start spawn_tunnel remote_to_local "$remote" "${input_topics[@]}" ||
+          ! inst_start spawn_tunnel local_to_remote "$remote" "${output_topics[@]}"; then
+               return 1
+       fi
+
+       return 0
+}
+
+{
+       if ! . toolbox.sh; then
+               exit 1
+       fi
+
+       if ! include "log" "opt" "inst" "ipc"; then
+               exit 1
+       fi
+
+       main "$@"
+       exit "$?"
+}