about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2020-04-30 15:45:19 -0500
committerCase Duckworth2020-05-03 18:55:31 -0500
commitafd8272ac0a049d6b7da4b3370b476613ce9a3cf (patch)
tree65cab1269b1d84a1f383c0faf4b26042a08f1f6b
parentUpdate style (diff)
downloadmrgrctrnl-afd8272ac0a049d6b7da4b3370b476613ce9a3cf.tar.gz
mrgrctrnl-afd8272ac0a049d6b7da4b3370b476613ce9a3cf.zip
Version 0.2
A LOT of changes here. Mostly I tried to make it more robust, and to
actually quit when I want it to quit. I also rewrote a lot of the
functions and stuff. I feel pretty happy with it now, enough to make it
an actual project on sourcehut.
-rwxr-xr-xmrgrctrnl200
1 files changed, 120 insertions, 80 deletions
diff --git a/mrgrctrnl b/mrgrctrnl index d51be58..796470c 100755 --- a/mrgrctrnl +++ b/mrgrctrnl
@@ -1,95 +1,135 @@
1#!/bin/sh 1#!/bin/sh
2# mrgrctrnl 2# mrgrctrnl: configurable ssh tunneler
3# configurable ssh tunneler 3# Author: Case Duckworth <acdw@acdw.net>
4# by Case Duckworth <acdw@acdw.net> 4# Version: 0.2
5# version 0.1 5# License: MIT
6# LICENSE: MIT
7 6
8usage() { 7PRGN="${0##*/}"
9 cat <<-END
10 mrgrctrnl: make magic ssh tunnels
11 usage: mrgrctrnl [-h] [-c CONF] [-d] [-k]
12 8
13 -h show this help 9usage() {
14 -c CONF use config file CONF. 10 cat <<END
15 . default: \$XDG_CONFIG_HOME/mrgrctrnl/config 11$PRGN: make magic ssh tunnels
16 -d do a dry run: don't actually tunnel 12usage: $PRGN [-h] [-k]
17 -k kill all processes and exit 13 $PRGN [-n] [-c CONF | -s SSH]
18 14
19 END 15options:
20 exit "${1:-0}" 16 -h show this help
17 -k kill all processes and exit
18 -r restart $PRGN
19 -n do a dry run: just print what would happen
20 -c CONFIG use a different CONFIG file instead of
21 \$XDG_CONFIG_HOME/$PRGN/config
22 -s CMDLINE directly input an ssh CMDLINE --
23 don't load the config file.
24END
21} 25}
22 26
23die() { 27# entry point
24 [ "$#" -eq 0 ] && exit 1 28main() {
25 case "$1" in 29 __CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/$PRGN/config"
26 0-9*) 30 __SSHCMD="-N \"\$user@\$machine\" -L \"\$local:\$remote\""
27 ec="$1" 31 __PIDF="/tmp/$PRGN.pid"
28 shift 32 _run=true
29 ;; 33 _quiet=false
30 *) ec=1 ;; 34 _use_config=true
31 esac
32 printf '!!%s: %s\n' "mrgrctrnl" "$*"
33 exit "$ec"
34}
35 35
36demolish_tunnels() { 36 while getopts hqkrnc:s: OPT; do
37 printf '%s...' "Demolishing tunnels" 37 case "$OPT" in
38 while read -r pid; do 38 h)
39 [ -z "$pid" ] && continue 39 usage
40 kill "$pid" 2>/dev/null 40 exit 0
41 done <"$pidf" 41 ;;
42 rm "$pidf" 42 q) _quiet=true ;;
43 sleep 3 43 k)
44 printf '%s.\n' "Done" 44 tear_down
45} 45 pkill -x "$PRGN"
46 exit
47 ;;
48 r)
49 tear_down
50 exec "$PRGN"
51 ;;
52 n) _run=false ;;
53 c) __CONFIG="$OPTARG" ;;
54 s)
55 __SSHCMD="$OPTARG"
56 _use_config=false
57 ;;
58 *)
59 usage
60 exit 1
61 ;;
62 esac
63 done
46 64
47config="${XDG_CONFIG_HOME:=$HOME/.config}/mrgrctrnl/config" 65 if $_use_config && [ ! -r "$__CONFIG" ]; then
48pidf=/tmp/mrgrctrnl.pid 66 echo "!! $PRGN: Cannot find config file '$__CONFIG'."
49dry_run=false 67 echo "Aborting."
68 exit 2
69 fi
50 70
51while getopts hc:dk opt; do 71 if $_use_config; then
52 case "$opt" in 72 awk '{sub(/#.*$/,"");print}' "$__CONFIG" |
53 h) usage ;; 73 while read -r machine user local remote key rest; do
54 c) config="$OPTARG" ;; 74 if [ -z "$machine" ] || [ -z "$user" ] ||
55 d) dry_run=true ;; 75 [ -z "$local" ] || [ -z "$remote" ]; then
56 k) 76 continue
57 demolish_tunnels 77 fi
58 pkill -x mrgrctrnl
59 exit
60 ;;
61 \?) usage 2 ;;
62 *) usage 2 ;;
63 esac
64done
65shift "$((OPTIND - 1))"
66 78
67[ -f "$config" ] || die "Need a config! Edit $config" 79 # shellcheck disable=2030
68if [ -e "$pidf" ] && ! "$dry_run"; then 80 if [ -n "$key" ]; then
69 demolish_tunnels 81 __SSHCMD="$__SSHCMD -i \"$key\""
70fi 82 fi
83 if [ -n "$rest" ]; then
84 __SSHCMD="$__SSHCMD $rest"
85 fi
71 86
72awk '{sub(/#.*$/,"");print}' "$config" | 87 eval "tunnel $__SSHCMD" &
73 while read -r machine user local remote key rest; do 88 done
74 if [ -z "$machine" ] || [ -z "$user" ] || 89 else
75 [ -z "$local" ] || [ -z "$remote" ]; then 90 # shellcheck disable=2031
76 continue 91 eval "tunnel $__SSHCMD" &
77 fi 92 fi
78 93
79 set -- -N "$user@$machine" -L "$local:$remote" 94 wait
80 [ -n "$key" ] && set -- "$@" -i "$key" 95}
81 #shellcheck disable=2086
82 [ -n "$rest" ] && set -- "$@" $rest
83 96
84 echo ssh "$@" 97tunnel() {
98 # shellcheck disable=2086
99 $_quiet || echo ssh "$@"
100 $_run && {
101 touch "$__PIDF"
102 while [ -e "$__PIDF" ]; do
103 grep -q -e "$*" "$__PIDF" && {
104 sleep 3
105 continue
106 }
107 # shellcheck disable=2015
108 if ssh "$@" & then
109 printf '%s\t%s\n' "$!" "$*" >>"$__PIDF"
110 else
111 badpid="$!"
112 kill "$badpid"
113 sed "/^$badpid/d" "$__PIDF" >"$__PIDF~" &&
114 mv "$__PIDF~" "$__PIDF"
115 continue
116 fi
117 sleep 3
118 done
119 }
120}
85 121
86 "$dry_run" || { 122tear_down() {
87 while :; do 123 printf '%s...' "Killing extant tunnels"
88 ssh "$@" 124 if [ -e "$__PIDF" ]; then
89 echo "$!" >>"$pidf" 125 while read -r pid _; do
90 sleep 5 126 kill "$pid" 2>/dev/null
91 done & 127 done <"$__PIDF"
92 } 128 rm "$__PIDF"
93 done 129 else
130 pkill -x ssh
131 fi
132 echo Done.
133}
94 134
95wait 135main "$@"