pastebin - collaborative debugging tool
rovema.kpaste.net RSS

Difference between
modified post 56a4a5f43 by Anonymous on Tue 11th Jul 2023 16:40
original post fa485 by Anonymous on Mon 27th Feb 2023 13:58
Download diff
Show old version | new version | both versions

    
11
#!/usr/bin/ksh93
22
#
33
# sshnfs - remote login client with NFSv4 forwarding
44
#
55
# Example usage:
66
# $ ksh sshnfs.ksh -o NFSURL=nfs://localhost/export/home/rmainz root@10.49.20.207 #
77
# $ ksh sshnfs.ksh -o NFSURL=nfs://derfwpc5131/export/home/rmainz -o NFSJumphost=rmainz@derfwpc5131,roland.mainz@derfwnb8353 -J rmainz@derfwpc5131,roland.mainz@derfwnb8353 root@10.49.20.207
88
# $ ksh sshnfs.ksh -o NFSURL=nfs://derfwpc5131/export/home/rmainz target@fe80::d6f5:27ff:fe2b:8588%enp2s0
9+
# $ ksh sshnfs.ksh -o NFSServerSSHLoginName=root -o NFSURL=nfs://derfwpc5131/export/home/rmainz root@10.49.28.56
911
#
1012
# Written by Roland Mainz <roland.mainz@nrubsig.org>
1113
#
1214
1315
#
1416
# simple netstat -n parser
1517
#
1618
function netstat_list_connections
1719
{
1820
	set -o nounset
1921
	nameref data=$1
2022
2123
	compound out=( typeset stdout stderr ; integer res )
2224
2325
	out.stderr="${ { out.stdout="${ LC_ALL='POSIX' PATH='/usr/bin:/bin' netstat -a -n ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
2426
	if (( out.res != 0 )) || [[ ${out.stderr} != '' ]] ; then
2527
		return 1
2628
	fi
2729
2830
	typeset -a data.connections
2931
	typeset l
3032
	integer dci=0 # data.connections array index
3133
3234
	while read l ; do
3335
		leftover="${l/~(Elrx)
3436
		(?: # non-capturing group
3537
			#
3638
			# regex group for tcp,udp
3739
			#
38-
			(tcp|tcp6|udp|udp6|raw6)	# Proto
40+
			(tcp|tcp6|udp|udp6|raw|raw6|sctp|sctp6)	# Proto
3941
			[[:space:]]+
4042
			([[:digit:]]+)			# Recv-Q
4143
			[[:space:]]+
4244
			([[:digit:]]+)			# Send-Q
4345
			[[:space:]]+
4446
			([^[:space:]]+)			# Local Address
4547
			[[:space:]]+
4648
			([^[:space:]]+)			# Foreign Address
4749
			(?:
4850
				|
4951
				[[:space:]]+
5052
				([^[:space:]]*?) 	# State (Optional)
5153
			)
5254
		|
5355
			#
5456
			# regex for unix
5557
			#
5658
			(unix)				# Proto
5759
			[[:space:]]+
5860
			([[:digit:]]+)			# RefCnt
5961
			[[:space:]]+
6062
			(\[.+?\])			# Flags
6163
			[[:space:]]+
6264
			([^[:space:]]+) 		# Type
6365
			[[:space:]]+
6466
			([^[:space:]]*?)		# State (optional)
6567
			[[:space:]]+
6668
			([[:digit:]]+)			# I-Node
6769
			(?:
6870
				|
6971
				[[:space:]]+
7072
				([^[:space:]]+)		# Path (optional)
7173
			)
7274
		)
7375
			/X}"
7476
7577
		# If the regex above did not match then .sh.match
7678
		# remains untouched, so we might see data from the
7779
		# previous round.
7880
		# So we check the "leftover" var whether it just
7981
		# contains the dummy value of "X" to indicate a
8082
		# successful regex match
8183
		if [[ "$leftover" == 'X' ]] ; then
8284
			#print -v .sh.match
8385
8486
			if [[ "${.sh.match[1]-}" != '' ]] ; then
8587
				nameref dcn=data.connections[$dci]
8688
8789
				typeset dcn.proto="${.sh.match[1]}"
8890
				typeset dcn.recv_q="${.sh.match[2]}"
8991
				typeset dcn.send_q="${.sh.match[3]}"
9092
				typeset dcn.local_address="${.sh.match[4]}"
9193
				typeset dcn.foreign_address="${.sh.match[5]}"
9294
				typeset dcn.state="${.sh.match[6]}"
9395
				((dci++))
9496
			elif [[ "${.sh.match[7]-}" != '' ]] ; then
9597
				nameref dcn=data.connections[$dci]
9698
9799
				typeset dcn.proto="${.sh.match[7]}"
98100
				typeset dcn.refcnt="${.sh.match[8]}"
99101
				typeset dcn.flags="${.sh.match[9]}"
100102
				typeset dcn.type="${.sh.match[10]}"
101103
				[[ "${.sh.match[11]}" != '' ]] && typeset dcn.state="${.sh.match[11]}"
102104
				typeset dcn.inode="${.sh.match[12]}"
103105
				[[ "${.sh.match[13]}" != '' ]] && typeset dcn.path="${.sh.match[13]}"
104106
				((dci++))
105107
			fi
106108
		else
107109
			true
108110
			#printf $"leftover=%q\n" "${leftover}"
109111
		fi
110112
	done <<<"${out.stdout}"
111113
112114
	return 0
113115
}
114116
115117
function netstat_list_active_local_tcp_connections
116118
{
117119
	set -o nounset
118120
	nameref ar=$1
119121
	compound c
120122
	integer port
121123
	integer i
122124
123125
	netstat_list_connections c || return 1
124126
	#print -v c
125127
126128
	[[ -v ar ]] || integer -a ar
127129
128130
	for i in "${!c.connections[@]}" ; do
129131
		nameref n=c.connections[$i]
130132
131133
		# look for only for TCP connections which match
132134
		# 127.0.*.* or IPv6 ::1 for localhost
133135
		# 0.0.0.0 or IPv6 :: for all addresses (e.g. servers)
134136
		if [[ "${n.proto}" == ~(El)tcp && \
135137
			"${n.local_address}" == ~(Elr)((127\.0\..+|::1)|(::|0\.0\.0\.0|)):[[:digit:]]+ ]] ; then
136138
137139
			port="${n.local_address##*:}"
138140
			#printf $"port = %d\n" port
139141
140142
			(( ar[port]=1 ))
141143
		fi
142144
	done
143145
144146
	return 0
145147
}
146148
147149
function netstat_find_next_free_local_tcp_port
148150
{
149151
	set -o nounset
150152
	compound c=( integer -a ar )
151153
	nameref ret_free_port=$1
152154
	integer start_port
153155
	integer end_port
154156
	integer i
155157
156158
	netstat_list_active_local_tcp_connections c.ar || return 1
157159
158160
	#print -v c
159161
160162
	(( start_port=$2 ))
161163
	if (( $# > 2 )) ; then
162164
		(( end_port=$3 ))
163165
	else
164166
		(( end_port=65535 ))
165167
	fi
166168
167169
	for ((i=start_port ; i < end_port ; i++ )) ; do
168170
		if [[ ! -v c.ar[i] ]] ; then
169171
			(( ret_free_port=i ))
170172
			return 0
171173
		fi
172174
	done
173175
174176
	return 1
175177
}
176178
177179
#
178180
# parse url
179181
#
180182
# returns:
181183
# data.protocol
182184
# data.host
183185
# data.port (optional)
184186
# data.path
185187
#
186188
function parse_url
187189
{
188190
	typeset url="$2"
189191
	typeset leftover
190192
	nameref data="$1"
191193
192194
	# ~(E) is POSIX extended regular expression matching (instead of
193195
	# shell pattern)
194196
	leftover="${url//~(Elr)(.+?):\/\/(.+?)(?:|:([[:digit:]]+))(?:\/(.*?))?/X}"
195197
196198
	# All parsed data should be captured via eregex in .sh.match - if
197199
	# there is anything left (except the 'X') then the input string did not
198200
	# properly match the eregex
199201
	[[ "$leftover" == 'X' ]] || { print -u2 -f $"%s: Parser error\n" "$0" ; return 1 ; }
200202
201203
	data.protocol="${.sh.match[1]}"
202204
	data.host="${.sh.match[2]}"
203-
	# bug: should be [[ -v .sh.match[3] }}, but ksh93u has bugs
205+
	# bug: should be [[ -v .sh.match[3] ]], but ksh93u has bugs
204206
	[[ "${.sh.match[3]}" != '' ]] && integer data.port="${.sh.match[3]}"
205207
	data.path="${.sh.match[4]}"
206208
207209
	return 0
208210
}
209211
210212
function parse_nfs_url
211213
{
212214
	typeset url="$2"
213215
	nameref data="$1"
214216
215217
	parse_url data "$url" || return 1
216218
217219
	[[ "${data.protocol}" == 'nfs' ]]	|| { print -u2 -f $"%s: Not a NFS url\n" "$0" ; return 1 ; }
218220
	[[ "${data.host}" != '' ]]		|| { print -u2 -f $"%s: NFS hostname missing\n" "$0" ; return 1 ; }
219221
	[[ "${data.path}" != '' ]]		|| { print -u2 -f $"%s: NFS path missing\n" "$0" ; return 1 ; }
220222
221223
	if [[ ! -v data.port ]] ; then
222224
		# use # default NFSv4 TCP port number (see
223225
		# $ getent services nfs #)
224226
		integer data.port=2049
225227
	fi
226228
227229
	return 0
228230
}
229231
230232
231233
function main
232234
{
233235
	set -o nounset
234236
	typeset mydebug=false # fixme: should be "bool" for ksh93v
235237
	integer i
236238
	integer retval
237239
	compound c=(
240+
		# User name for SSH login to NFS server
238243
		# port on THIS machine
239244
		integer local_forward_port
240245
241246
		# TCP port on destination machine where we forward the
242247
		# NFS port from the server
243248
		integer destination_nfs_port=33049
244249
245250
		typeset ssh_control_socket_name="/tmp/sshnfs_ssh-control-socket_logname${LOGNAME}_ppid${PPID}_pid$$"
246251
	)
247252
248253
	#
249254
	# find free local forwarding port...
250255
	#
251256
	(( i=34049 ))
252257
	netstat_find_next_free_local_tcp_port c.local_forward_port $i
253258
254259
	#
255260
	# ... and adjust c.destination_nfs_port by the same offset
256261
	# we do that so that multiple sshweb.ksh logins to the same
257262
	# machine do try to use the same ports on that machine
258263
	#
259264
	(( c.destination_nfs_port += c.local_forward_port-i ))
260265
	${mydebug} && printf $"debug: c.local_forward_port=%d, c.destination_nfs_port=%d\n" \
261266
		c.local_forward_port \
262267
		c.destination_nfs_port
263268
264-
	typeset c.args=( "$@" )
269+
	#
270+
	# Expand SSHNFS_OPTIONS before arguments given to sshnfs.ksh
265274
266275
	for ((i=0 ; i < ${#c.args[@]} ; i++)) ; do
267276
		if [[ "${c.args[i]}" == '-o' ]] ; then
268277
			case "${c.args[i+1]-}" in
269-
				'NFSURL='*)
278+
				~(Eli)NFSServerSSHLoginName=)
279+
					c.nfsserver_ssh_login_name="${c.args[i+1]/~(Eli)NFSServerSSHLoginName=}"
274281
					unset c.args[$i] c.args[$((i+1))]
275282
					((i++))
276283
					;;
279-
					c.ssh_jumphost_args+=( "-J" "${c.args[i+1]#NFSJumphost=}" )
280-
					unset c.args[$i] c.args[$((i+1))]
281-
					((i++))
282-
					;;
283-
			esac
284-
		fi
285-
	done
284+

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at