Browse Source

sshtunnel: switch to procd

This changeset removes the shell wrapper the package used previously,
and uses the instance-management abilities of procd to track ssh
processes. Many fixes and improvements were integrated from the
package maintainer's branch at

https://github.com/nunojpg/packages/tree/sshtunnel

Signed-off-by: Kiril Zyapkov <kiril.zyapkov@gmail.com>
Kiril Zyapkov 9 years ago
parent
commit
9d3877d446
3 changed files with 157 additions and 170 deletions
  1. 3
    6
      net/sshtunnel/Makefile
  2. 154
    143
      net/sshtunnel/files/sshtunnel.init
  3. 0
    21
      net/sshtunnel/files/sshtunnel.sh

+ 3
- 6
net/sshtunnel/Makefile View File

@@ -1,16 +1,15 @@
1 1
 #
2
-# Copyright (C) 2010-2014 OpenWrt.org
2
+# Copyright (C) 2010-2015 OpenWrt.org
3 3
 # Copyright (C) 2010 segal.di.ubi.pt
4 4
 #
5 5
 # This is free software, licensed under the GNU General Public License v2.
6 6
 # See /LICENSE for more information.
7
-#
8 7
 
9 8
 include $(TOPDIR)/rules.mk
10 9
 
11 10
 PKG_NAME:=sshtunnel
12
-PKG_VERSION:=3
13
-PKG_RELEASE:=3
11
+PKG_VERSION:=4
12
+PKG_RELEASE:=1
14 13
 PKG_LICENSE:=GPL-2.0+
15 14
 
16 15
 PKG_MAINTAINER:=Nuno Goncalves <nunojpg@gmail.com>
@@ -39,8 +38,6 @@ endef
39 38
 define Package/sshtunnel/install
40 39
 	$(INSTALL_DIR) $(1)/etc/init.d
41 40
 	$(INSTALL_BIN) ./files/sshtunnel.init $(1)/etc/init.d/sshtunnel
42
-	$(INSTALL_DIR) $(1)/usr/bin
43
-	$(INSTALL_BIN) ./files/sshtunnel.sh $(1)/usr/bin/
44 41
 	$(INSTALL_DIR) $(1)/etc/config
45 42
 	$(INSTALL_DATA) ./files/uci_sshtunnel $(1)/etc/config/sshtunnel
46 43
 endef

+ 154
- 143
net/sshtunnel/files/sshtunnel.init View File

@@ -1,18 +1,30 @@
1 1
 #!/bin/sh /etc/rc.common
2
+#
3
+# Copyright (C) 2010-2015 OpenWrt.org
4
+# Copyright (C) 2010 segal.di.ubi.pt
5
+#
2 6
 
3 7
 START=99
4 8
 STOP=01
9
+USE_PROCD=1
5 10
 
6
-PIDFILE="/tmp/run/sshtunnel"
11
+PROG=/usr/bin/ssh
7 12
 
13
+_log() {
14
+	logger -p daemon.info -t sshtunnel "$@"
15
+}
16
+
17
+_err() {
18
+	logger -p daemon.err -t sshtunnel "$@"
19
+}
8 20
 
9 21
 append_params() {
10
-	local p; local v; local args;
22
+	local p v args
11 23
 	for p in $*; do
12 24
 		eval "v=\$$p"
13 25
 		[ -n "$v" ] && args="$args -o $p=$v"
14 26
 	done
15
-	
27
+
16 28
 	ARGS_options="${args# *}"
17 29
 }
18 30
 
@@ -24,179 +36,178 @@ append_string() {
24 36
 	eval "$varname=\$new"
25 37
 }
26 38
 
39
+validate_server_section() {
40
+	uci_validate_section sshtunnel server "$1" \
41
+		'user:string(1)' \
42
+		'hostname:host' \
43
+		'port:port' \
44
+		'retrydelay:min(1):60' \
45
+		'PKCS11Provider:file' \
46
+		'CheckHostIP:or("yes", "no")' \
47
+		'Compression:or("yes", "no")' \
48
+		'CompressionLevel:range(1,9)' \
49
+		'IdentityFile:file' \
50
+		'LogLevel:or("QUIET", "FATAL", "ERROR", "INFO", "VERBOSE", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3"):INFO' \
51
+		'ServerAliveCountMax:min(1)' \
52
+		'ServerAliveInterval:min(1)' \
53
+		'StrictHostKeyChecking:or("yes", "no")' \
54
+		'TCPKeepAlive:or("yes", "no")' \
55
+		'VerifyHostKeyDNS:or("yes", "no")'
56
+}
57
+
58
+validate_tunnelR_section() {
59
+	uci_validate_section sshtunnel tunnelR "$1" \
60
+		'remoteaddress:or(host, "*"):*' \
61
+		'remoteport:port' \
62
+		'localaddress:host' \
63
+		'localport:port'
64
+}
65
+
66
+validate_tunnelL_section() {
67
+	uci_validate_section sshtunnel tunnelL "$1" \
68
+		'remoteaddress:host' \
69
+		'remoteport:port' \
70
+		'localaddress:or(host, "*"):*' \
71
+		'localport:port'
72
+}
73
+
74
+validate_tunnelD_section() {
75
+	uci_validate_section sshtunnel tunnelD "$1" \
76
+		'localaddress:or(host, "*"):*' \
77
+		'localport:port'
78
+}
79
+
80
+validate_tunnelW_section() {
81
+	uci_validate_section sshtunnel tunnelW "$1" \
82
+		'vpntype:or("ethernet", "point-to-point"):point-to-point' \
83
+		'localdev:or("any", min(1))' \
84
+		'remotedev:or("any", min(1))'
85
+}
86
+
27 87
 load_tunnelR() {
28
-	config_get section_server $1 server
29
-	[ "$server" = "$section_server" ] || return 0 # continue to read next section if this is not for the current server
30
-	let count++ # count nr of valid sections to make sure there are at least one
31
-
32
-	config_get remoteaddress $1 remoteaddress "*"
33
-	config_get remoteport 	$1 remoteport
34
-	config_get localaddress $1 localaddress
35
-	config_get localport	$1 localport
36
-	
37
-        [ "$remoteport" -gt 0 ] || append_string "error" "[tunnelR: $1]remoteport must be a positive integer" "; "
38
-        [ "$localport" -gt 0 ] 	|| append_string "error" "[tunnelR: $1]localport must be a positive integer" "; "
39
-	[ -n "$error" ] && return 1
88
+	config_get section_server "$1" "server"
89
+
90
+	# continue to read next section if this is not for the current server
91
+	[ "$server" = "$section_server" ] || return 0
92
+
93
+	# validate and load this remote tunnel config
94
+	local remoteaddress remoteport localaddress localport
95
+	validate_tunnelR_section "$1" || { _err "tunnelR ${1}: validation failed"; return 1; }
96
+
97
+	[ -n "$remoteport" -a -n "$localport" -a -n "$remoteaddress" ] || { _err "tunnelR ${1}: missing required options"; return 1; }
40 98
 
99
+	# count nr of valid sections to make sure there are at least one
100
+	let count++
101
+
102
+	_log "tunnelR at ${server}: -R $remoteaddress:$remoteport:$localaddress:$localport"
41 103
 	append_string "ARGS_tunnels" "-R $remoteaddress:$remoteport:$localaddress:$localport"
42 104
 }
43 105
 
44 106
 load_tunnelL() {
45
-	config_get section_server $1 server
46
-	[ "$server" = "$section_server" ] || return 0 # continue to read next section if this is not for the current server
47
-	let count++ # count nr of valid sections to make sure there are at least one
107
+	config_get section_server "$1" "server"
108
+
109
+	# continue to read next section if this is not for the current server
110
+	[ "$server" = "$section_server" ] || return 0
48 111
 
49
-	config_get localaddress $1 localaddress "*"	
50
-	config_get localport	$1 localport
51
-	config_get remoteaddress $1 remoteaddress
52
-	config_get remoteport 	$1 remoteport
112
+	# validate and load this remote tunnel config
113
+	local remoteaddress remoteport localaddress localport
114
+	validate_tunnelL_section "$1" || { _err "tunnelL ${1}: validation failed"; return 1; }
53 115
 
54
-        [ "$remoteport" -gt 0 ] || append_string "error" "[tunnelL: $1]remoteport must be a positive integer" "; "
55
-        [ "$localport" -gt 0 ] 	|| append_string "error" "[tunnelL: $1]localport must be a positive integer" "; "
56
-	[ -n "$error" ] && return 1
116
+	[ -n "$remoteport" -a -n "$localport" -a -n "$remoteaddress" ] || { _err "tunnelL ${1}: missing required options"; return 1; }
57 117
 
118
+	# count nr of valid sections to make sure there are at least one
119
+	let count++
120
+
121
+	_log "tunnelL at ${server}: -L $localaddress:$localport:$remoteaddress:$remoteport"
58 122
 	append_string "ARGS_tunnels" "-L $localaddress:$localport:$remoteaddress:$remoteport"
59 123
 }
60 124
 
61 125
 load_tunnelD() {
62
-	config_get section_server $1 server
63
-	[ "$server" = "$section_server" ] || return 0 # continue to read next section if this is not for the current server
64
-	let count++ # count nr of valid sections to make sure there are at least one
126
+	config_get section_server "$1" "server"
127
+
128
+	# continue to read next section if this is not for the current server
129
+	[ "$server" = "$section_server" ] || return 0
65 130
 
66
-	config_get localaddress $1 localaddress "*"
67
-	config_get localport	$1 localport
131
+	# validate and load this remote tunnel config
132
+	local localaddress localport
133
+	validate_tunnelD_section "$1" || { _err "tunnelD ${1}: validation failed"; return 1; }
68 134
 
69
-        [ "$localport" -gt 0 ] 	|| append_string "error" "[tunnelD: $1]localport must be a positive integer" "; "
70
-	[ -n "$error" ] && return 1
135
+	[ -n "$localport" ] || { _err "tunnelD ${1}: missing localport"; return 1; }
71 136
 
137
+	# count nr of valid sections to make sure there are at least one
138
+	let count++
139
+
140
+	_log "proxy via ${server}: -D $localaddress:$localport"
72 141
 	append_string "ARGS_tunnels" "-D $localaddress:$localport"
73 142
 }
74 143
 
75 144
 load_tunnelW() {
76
-        config_get section_server $1 server
77
-        [ "$server" = "$section_server" ] || return 0 # continue to read next section if this is not for the current server
78
-        let count++ # count nr of valid sections to make sure there are at least one
145
+	config_get section_server "$1" "server"
146
+
147
+	# continue to read next section if this is not for the current server
148
+	[ "$server" = "$section_server" ] || return 0
149
+
150
+	# validate and load this remote tunnel config
151
+	local localdev remotedev vpntype
152
+	validate_tunnelW_section "$1" || { _err "tunnelW ${1}: validation failed"; return 1; }
153
+
154
+	[ -n "$vpntype" -a -n "$localdev" -a -n "$remotedev" ] || { _err "tunnelW $1: missing or bad options"; return 1; }
79 155
 
80
-        config_get localdev     $1 localdev "*"
81
-        config_get remotedev    $1 remotedev "*"
82
-        config_get vpntype      $1 vpntype "*"
156
+	[ "$user" == "root" ] || { _err "tunnelW ${1}: root is required for tun"; return 1; }
83 157
 
84
-        [ "$vpntype" == "ethernet" ] || [ "$vpntype" == "point-to-point" ] || append_string "error" "[tunnelW: $1] vpntype must be \"ethernet\" (tap) or \"pointopoint\" (tun)" "; "
85
-        [ "$localdev" == "any" ] || [ "$localdev" -ge 0 ] || append_string "error" "[tunnelW: $1] localdev must be an integer or \"any\"" "; "
86
-        [ "$remotedev" == "any" ] || [ "$remotedev" -ge 0 ] || append_string "error" "[tunnelW: $1] remotedev must be an integer or \"any\"" "; "
87
-        [ "$user" == "root" ] || logger -p user.warn -t "sshtunnel" "warning: root is required unless the tunnel device has been created manually"
88
-        [ -n "$error" ] && return 1
158
+	# count nr of valid sections to make sure there are at least one
159
+	let count++
89 160
 
90
-        append_string "ARGS_tunnels" "-w $localdev:$remotedev -o Tunnel=$vpntype"
161
+	_log "tunnelW to ${server}: -w $localdev:$remotedev -o Tunnel=$vpntype"
162
+	append_string "ARGS_tunnels" "-w $localdev:$remotedev -o Tunnel=$vpntype"
91 163
 }
92 164
 
93 165
 load_server() {
94 166
 	server="$1"
167
+	local user hostname port retrydelay PKCS11Provider CheckHostIP Compression \
168
+		CompressionLevel IdentityFile LogLevel ServerAliveCountMax \
169
+		ServerAliveInterval StrictHostKeyChecking TCPKeepAlive VerifyHostKeyDNS
95 170
 
96
-	config_get user 	$1 user
97
-	config_get hostname 	$1 hostname
98
-	config_get port		$1 port		"22"
99
-	config_get retrydelay 	$1 retrydelay	"60"
100
-	config_get PKCS11Provider	$1 PKCS11Provider
101
-	config_get CheckHostIP		$1 CheckHostIP
102
-	config_get Compression		$1 Compression
103
-	config_get CompressionLevel 	$1 CompressionLevel
104
-	config_get IdentityFile		$1 IdentityFile
105
-	config_get LogLevel 		$1 LogLevel
106
-	config_get ServerAliveCountMax 	$1 ServerAliveCountMax
107
-	config_get ServerAliveInterval 	$1 ServerAliveInterval
108
-	config_get StrictHostKeyChecking $1 StrictHostKeyChecking
109
-	config_get TCPKeepAlive		$1 TCPKeepAlive
110
-	config_get VerifyHostKeyDNS 	$1 VerifyHostKeyDNS
111
-		
112
-	error=""
113
-        [ -n "$user" ] \
114
-		|| append_string "error" "user is not set" "; "
115
-        [ -n "$hostname" ] \
116
-		|| append_string "error" "hostname is not set" "; "
117
-        [ "$retrydelay" -ge 1 ] \
118
-		|| append_string "error" "retrydelay must be a positive integer" "; "
119
-	[ -z "$PKCS11Provider" -o -f "$PKCS11Provider" ] \
120
-		|| append_string "error" "PKCS11Provider must be a pkcs11 shared library accessible" "; "
121
-	[ -z "$CheckHostIP" -o "$CheckHostIP"="yes" -o "$CheckHostIP"="no" ] \
122
-		|| append_string "error" "CheckHostIP must be 'yes' or 'no'" "; "
123
-	[ -z "$Compression" -o "$Compression"="yes" -o "$Compression"="no" ] \
124
-		|| append_string "error" "Compression must be 'yes' or 'no'" "; "
125
-	[ -z "$CompressionLevel" ] || [ "$CompressionLevel" -ge 1 -a "$CompressionLevel" -le 9 ] \
126
-		|| append_string "error" "CompressionLevel must be between 1 and 9" "; "
127
-	[ -z "$IdentityFile" -o -f "$IdentityFile" ] \
128
-		|| append_string "error" "IdentityFile $IdentityFile not accessible" "; "	
129
-	[ -z "$LogLevel" -o "$LogLevel" = "QUIET" -o "$LogLevel" = "FATAL" -o "$LogLevel" = "ERROR" -o \
130
-	 	"$LogLevel" = "INFO" -o "$LogLevel" = "VERBOSE" -o "$LogLevel" = "DEBUG" -o \
131
-		"$LogLevel" = "DEBUG1" -o "$LogLevel" = "DEBUG2" -o "$LogLevel" = "DEBUG3" ] \
132
-		|| append_string "error" "LogLevel is invalid" "; "
133
-	[ -z "$ServerAliveCountMax" ] || [ "$ServerAliveCountMax" -ge 1 ] \
134
-		|| append_string "error" "ServerAliveCountMax must be greater or equal than 1" "; "
135
-	[ -z "$ServerAliveInterval" ] || [ "$ServerAliveInterval" -ge 0 ] \
136
-		|| append_string "error" "ServerAliveInterval must be greater or equal than 0" "; "
137
-	[ -z "$StrictHostKeyChecking" -o "$StrictHostKeyChecking" = "yes" -o "$StrictHostKeyChecking" = "ask" -o "$StrictHostKeyChecking" = "no" ] \
138
-		|| append_string "error" "StrictHostKeyChecking must be 'yes', 'ask' or 'no'" "; "
139
-	[ -z "$TCPKeepAlive" -o "$TCPKeepAlive" = "yes" -o "$TCPKeepAlive" = "no" ] \
140
-		|| append_string "error" "TCPKeepAlive must be 'yes' or 'no'" "; "
141
-	[ -z "$VerifyHostKeyDNS" -o "$VerifyHostKeyDNS" = "yes" -o "$VerifyHostKeyDNS" = "no" ] \
142
-		|| append_string "error" "VerifyHostKeyDNS must be 'yes' or 'no'" "; "
143
-
144
-	[ -n "$error" ] && { logger -p user.err -t "sshtunnel" "tunnels to $server not started - $error"; return; }
145
-        
171
+	validate_server_section "$server" || { _err "server ${server}: validation failed"; return 1; }
146 172
 
147 173
 	ARGS=""
148 174
 	ARGS_options=""
149
-        ARGS_tunnels=""
150
-
175
+	ARGS_tunnels=""
151 176
 	count=0
152
-        config_foreach load_tunnelR tunnelR && config_foreach load_tunnelL tunnelL && config_foreach load_tunnelD tunnelD
153
-	[ -n "$error" ] 	&& { logger -p user.err -t "sshtunnel" "tunnels to $server not started - $error"; return; }
154
-	[ "$count" -eq 0 ] 	&& { logger -p user.err -t "sshtunnel" "tunnels to $server not started - no tunnels defined"; return; }
155 177
 
156
-	append_params CheckHostIP Compression CompressionLevel IdentityFile LogLevel PKCS11Provider ServerAliveCountMax ServerAliveInterval StrictHostKeyChecking TCPKeepAlive VerifyHostKeyDNS
178
+	config_foreach load_tunnelR "tunnelR"
179
+	config_foreach load_tunnelL "tunnelL"
180
+	config_foreach load_tunnelD "tunnelD"
181
+	config_foreach load_tunnelW "tunnelW"
182
+	[ "$count" -eq 0 ] && { _err "tunnels to ${server} not started - no tunnels defined"; return 1; }
183
+
184
+	append_params CheckHostIP Compression CompressionLevel IdentityFile \
185
+		LogLevel PKCS11Provider ServerAliveCountMax ServerAliveInterval \
186
+		StrictHostKeyChecking TCPKeepAlive VerifyHostKeyDNS
187
+
157 188
 	ARGS="$ARGS_options -o ExitOnForwardFailure=yes -o BatchMode=yes -nN $ARGS_tunnels -p $port $user@$hostname"
158 189
 
159
-	/usr/bin/sshtunnel.sh "$ARGS" "$retrydelay" "$server" &
160
-	echo $! >> "${PIDFILE}.pids"
161
-	logger -p user.info -t "sshtunnel" "started tunnels to $server (pid=$!;retrydelay=$retrydelay)" 
162
-}
163
-
164
-stop() {
165
-        if [ -f "$PIDFILE".pids ]
166
-        then
167
-                logger -p user.info -t "sshtunnel" "stopping all tunnels"
168
-                
169
-                while read pid
170
-                do
171
-			kill "$pid"	# kill mother process first
172
-
173
-			[ -f "${PIDFILE}_${pid}.pid" ] && { # if ssh was running, kill it also (mother process could be in retry wait)
174
-				start-stop-daemon -K -p "${PIDFILE}_${pid}.pid"
175
-				rm "${PIDFILE}_${pid}.pid"
176
-			}
177
-			
178
-			logger -p daemon.info -t "sshtunnel[$pid]" "tunnel stopped"
179
-			
180
-		done < "${PIDFILE}.pids"
181
-
182
-		rm "${PIDFILE}.pids"
183
-
184
-                logger -p user.info -t "sshtunnel" "all tunnels stopped"
185
-        else
186
-                logger -p user.info -t "sshtunnel" "no tunnels running"
187
-        fi
188
-}
189
-
190
-start() {
191
-        [ -f "${PIDFILE}.pids" ] && stop
192
-        
193
-	config_load sshtunnel
194
-	if [ -n "$(uci show sshtunnel.@server[0])" ] # at least one server section exists
195
-	then        
196
-		logger -p user.info -t "sshtunnel" "starting all tunnels"
197
-		config_foreach load_server server       
198
-		logger -p user.info -t "sshtunnel" "all tunnels started"	
199
-	else
200
-		logger -p user.info -t "sshtunnel" "no servers defined"
201
-	fi
190
+	procd_open_instance "$server"
191
+	procd_set_param command "$PROG" $ARGS
192
+	procd_set_param stdout 1
193
+	procd_set_param stderr 1
194
+	procd_set_param respawn 0 "$retrydelay" 1
195
+	procd_close_instance
196
+}
197
+
198
+start_service() {
199
+	config_load "sshtunnel"
200
+	config_foreach load_server "server"
201
+}
202
+
203
+service_triggers() {
204
+	procd_add_reload_trigger "sshtunnel"
205
+
206
+	procd_open_validate
207
+	validate_server_section
208
+	validate_tunnelR_section
209
+	validate_tunnelL_section
210
+	validate_tunnelD_section
211
+	validate_tunnelW_section
212
+	procd_close_validate
202 213
 }

+ 0
- 21
net/sshtunnel/files/sshtunnel.sh View File

@@ -1,21 +0,0 @@
1
-#!/bin/sh 
2
-
3
-PIDFILE="/tmp/run/sshtunnel"
4
-
5
-args="$1"
6
-retrydelay="$2"
7
-server="$3"
8
-
9
-while true
10
-do
11
-	logger -p daemon.info -t "sshtunnel[$$][$server]" "connection started"
12
-	
13
-	start-stop-daemon -S -p "${PIDFILE}_${$}.pid" -mx ssh -- $args &>/tmp/log/sshtunnel_$$ 
14
-	
15
-	logger -p daemon.err -t "sshtunnel[$$][$server]" < /tmp/log/sshtunnel_$$
16
-	rm /tmp/log/sshtunnel_$$
17
-	logger -p daemon.info -t "sshtunnel[$$][$server]" "ssh exited with code $?, retrying in $retrydelay seconds"
18
-	rm "${PIDFILE}_${$}.pid"
19
-
20
-	sleep "$retrydelay" & wait
21
-done