pastebin - collaborative debugging tool
rovema.kpaste.net RSS


sshnfs - ssh with nfs forwarding
Posted by Anonymous on Wed 15th Feb 2023 12:56
raw | new post
view followups (newest first): sshnfs - ssh with nfs forwarding by Anonymous
modification of post by Anonymous (view diff)

  1. #!/usr/bin/ksh93
  2. #
  3. # sshnfs - remote login client with NFSv4 forwarding
  4. #
  5. # Example usage:
  6. # $ ksh sshnfs.ksh -o NFSURL=nfs://localhost/export/home/rmainz root@10.49.20.207 #
  7. # $ 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
  8. #
  9. # Written by Roland Mainz <roland.mainz@nrubsig.org>
  10. #
  11.  
  12. #
  13. # parse url
  14. #
  15. # returns:
  16. # data.protocol
  17. # data.host
  18. # data.port (optional)
  19. # data.path
  20. #
  21. function parse_url
  22. {
  23.         typeset url="$2"
  24.         typeset leftover
  25.         nameref data="$1"
  26.        
  27.         # ~(E) is POSIX extended regular expression matching (instead of
  28.         # shell pattern)
  29.         leftover="${url//~(Elr)(.+?):\/\/(.+?)(?:|:([[:digit:]]+))(?:\/(.*?))?/X}"
  30.        
  31.         # All parsed data should be captured via eregex in .sh.match - if
  32.         # there is anything left (except the 'X') then the input string did not
  33.         # properly match the eregex
  34.         [[ "$leftover" == 'X' ]] || { print -u2 -f $"%s: Parser error\n" "$0" ; return 1 ; }
  35.  
  36.         data.protocol="${.sh.match[1]}"
  37.         data.host="${.sh.match[2]}"
  38.         # bug: should be [[ -v .sh.match[3] }}, but ksh93u has bugs
  39.         [[ "${.sh.match[3]}" != '' ]] && integer data.port="${.sh.match[3]}"
  40.         data.path="${.sh.match[4]}"
  41.  
  42.         return 0
  43. }
  44.  
  45. function parse_nfs_url
  46. {
  47.         typeset url="$2"
  48.         nameref data="$1"
  49.        
  50.         parse_url data "$url" || return 1
  51.        
  52.         [[ "${data.protocol}" == 'nfs' ]]       || { print -u2 -f $"%s: Not a NFS url\n" "$0" ; return 1 ; }
  53.         [[ "${data.host}" != '' ]]              || { print -u2 -f $"%s: NFS hostname missing\n" "$0" ; return 1 ; }
  54.         [[ "${data.path}" != '' ]]              || { print -u2 -f $"%s: NFS path missing\n" "$0" ; return 1 ; }
  55.        
  56.         if [[ ! -v data.port ]] ; then
  57.                 # use # default NFSv4 TCP port number (see
  58.                 # $ getent services nfs #)
  59.                 integer data.port=2049
  60.         fi
  61.  
  62.         return 0
  63. }
  64.  
  65.  
  66. function main
  67. {
  68.         integer i
  69.         integer retval
  70.         compound c=(
  71.                 # port on THIS machine
  72.                 integer local_forward_port=34049
  73.  
  74.                 # TCP port on destination machine where we forward the
  75.                 # NFS port from the server
  76.                 integer destination_nfs_port=33049
  77.  
  78.                 # fixme: "/tmp" vs. "${XDG_RUNTIME_DIR:-/tmp}" ?
  79.                 typeset ssh_control_socket_name="/tmp/sshnfs_ssh-control-socket_${LOGNAME}_${PPID}_$$"
  80.         )
  81.  
  82.         #set -o xtrace
  83.         typeset mydebug=false # fixme: should be "bool" for ksh93v
  84.         set -o nounset
  85.  
  86.         typeset c.args=( "$@" )
  87.  
  88.         for ((i=0 ; i < ${#c.args[@]} ; i++)) ; do
  89.                 if [[ "${c.args[i]}" == '-o' ]] ; then
  90.                         case "${c.args[i+1]-}" in
  91.                                 'NFSURL='*)
  92.                                         unset c.nfs_server
  93.                                         compound c.nfs_server
  94.                                         typeset c.url="${c.args[i+1]#NFSURL=}"
  95.                                         parse_nfs_url c.nfs_server "${c.url}" || return 1
  96.                                         unset c.args[$i] c.args[$((i+1))]
  97.                                         ((i++))
  98.                                         ;;
  99.                                 'NFSJumphost='*)
  100.                                         [[ ! -v c.ssh_jumphost_args ]] && typeset -a c.ssh_jumphost_args
  101.                                         c.ssh_jumphost_args+=( "-J" "${c.args[i+1]#NFSJumphost=}" )
  102.                                         unset c.args[$i] c.args[$((i+1))]
  103.                                         ((i++))
  104.                                         ;;
  105.                         esac
  106.                 fi
  107.         done
  108.  
  109.         if [[ -v c.nfs_server ]] ; then
  110.                 # Forward NFS port from server to local machine
  111.                 # Notes:
  112.                 # - We use $ ssh -M ... # here as a way to terminate the port
  113.                 # forwarding process later using "-O exit" without the need
  114.                 # for a pid
  115.                 print -u2 -f $"# Please enter the login data for NFS server (%s):\n" \
  116.                         "root@${c.nfs_server.host}"
  117.                 ssh \
  118.                         -L "${c.local_forward_port}:localhost:${c.nfs_server.port}" \
  119.                         -M -S "${c.ssh_control_socket_name}" \
  120.                         -N \
  121.                         -f -o 'ExitOnForwardFailure=yes' \
  122.                         "${c.ssh_jumphost_args[@]}" \
  123.                         "root@${c.nfs_server.host}"
  124.                 if (( $? != 0 )) ; then
  125.                         print -u2 -f $"%s: NFS forwarding ssh failed with error code %d\n" "$0" $?
  126.                         return 1
  127.                 fi
  128.  
  129.                 # debug
  130.                 ${mydebug} && ssh -S "${c.ssh_control_socket_name}" -O 'check' "root@${c.nfs_server.host}"
  131.  
  132.                 print -u2 -f $"# Use this to mount the directory:\n"
  133.                 print -u2 -f $"# $ mkdir /mnt_nfs\n"
  134.                 print -u2 -f $"# $ mount -vvv -t nfs -o vers=4,port=%d localhost:/%s /mnt_nfs\n" \
  135.                         c.destination_nfs_port \
  136.                         "${c.nfs_server.path}"
  137.  
  138.                 # add NFS forwarding options to main ssh argument list
  139.                 c.args=(
  140.                         '-R' "${c.destination_nfs_port}:localhost:${c.local_forward_port}"
  141.                         '-o' 'ExitOnForwardFailure=yes'
  142.                         "${c.args[@]}"
  143.                 )
  144.         fi
  145.  
  146.         ${mydebug} && print -v c
  147.  
  148.         print -u2 -f $"# ssh login data for destination machine:\n"
  149.         ssh "${c.args[@]}" ; (( retval=$? ))
  150.  
  151.         if [[ -v c.nfs_server ]] ; then
  152.                 ssh -S "${c.ssh_control_socket_name}" -O 'exit' "root@${c.nfs_server.host}"
  153.         fi
  154.  
  155.         wait
  156.  
  157.         return $retval
  158. }
  159.  
  160. main "$@"
  161. exit $?
  162.  
  163. # EOF.

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