From 9f7f07c0337f183d60b509c6c67ea63c6ed9f66e Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Sat, 8 Oct 2022 13:41:40 +0900 Subject: [PATCH] utils/ipc-sshtunnel: Add script for establishing IPC-over-SSH tunnels 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 | 2 + utils/ipc-sshtunnel.sh | 143 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100755 utils/ipc-sshtunnel.sh diff --git a/Makefile b/Makefile index e84b654..9d7dabe 100644 --- 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 index 0000000..2c28c2b --- /dev/null +++ b/utils/ipc-sshtunnel.sh @@ -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 . + +_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 "$?" +} -- 2.47.3