@c -*-texinfo-*-
@c This file is part of Guile-SSH Reference Manual.
@c Copyright (C) 2015-2021 Artyom V. Poptsov
@c See the file guile-ssh.texi for copying conditions.

@node Tunnels
@section Tunnels

@cindex Tunnels

The following procedures from @code{(ssh tunnel)} module are a high-level API
built upon the basic port forwarding facilities for managing port forwards.

@deffn {Scheme Procedure} make-tunnel session [#:bind-address=''127.0.0.1''] #:port #:host [#:host-port=port] [#:reverse?=#f]
Make a new SSH tunnel using @var{session} from @var{bind-address} and
@var{port} to a @var{host} and @var{host-port}.

The procedure is capable of creating both direct and reverse port forwarding
tunnels; the type of a tunnel is determined by @var{reverse?} argument.  If
@var{reverse?} is set to @code{#f} then a reverse port forwarding tunnel will
be created.

Setting @var{reverse?} to @code{#t} changes the direction of the tunnel and a
reverse port forwarding tunnel will be created.  In this case a server
allocates a socket to listen to @var{port} on the remote side, and whenever a
connection is made to this port, the connection is forwarded over the secure
channel, and a connection is made to @var{host} and @var{host-port} from the
local machine.  @var{host} can be set to @code{#f} to tell the server to
listen on all addresses and known protocol families.  Setting a @var{port} to
0 tells the server to bind the first unprivileged port.

The procedure does not binds ports nor transfers data to the port (in case of
reverse port forwarding), you should start port forwarding by means of the
procedures that operate on a <tunnel> object -- e.g.  @code{start-forward} or
@code{call-with-ssh-forward}.

Return a new tunnel object.
@end deffn

@deffn {Scheme Procedure} tunnel? x
Return @code{#t} if @var{x} is an Guile-SSH tunnel, @code{#f} otherwise.
@end deffn

@deffn {Scheme procedure} tunnel-reverse? x
Check if @var{x} is a reverse port forwarding tunnel.
@end deffn

@deffn {Scheme procedure} tunnel-session tunnel
Get a session associated with a @var{tunnel}.
@end deffn

@deffn {Scheme Procedure} tunnel-bind-address tunnel
Get a source host of a @var{tunnel}.
@end deffn

@deffn {Scheme Procedure} tunnel-port tunnel
Get a local port of a @var{tunnel}.
@end deffn

@deffn {Scheme Procedure} tunnel-host tunnel
Get a remote host of a @var{tunnel}.
@end deffn

@deffn {Scheme Procedure} tunnel-host-port tunnel
Get a remote port of a @var{tunnel}.
@end deffn

@deffn {Scheme Procedure} start-forward tunnel
Start port forwarding on @var{tunnel}.  The procedure actually binds tunnel
ports and forwards data.
@end deffn

@deffn {Scheme Procedure} call-with-ssh-forward tunnel proc
Open a new @var{tunnel} and start port forwarding. @var{proc} is called with
an open channel as an argument. All I/O on the channel will be forwarded to
the remote host and port of a @var{tunnel}. Return the result the @var{proc}
call.

As a practical example, let's say you want to use
@url{https://www.gnu.org/software/guile-rpc/, Guile-RPC} over SSH. Here's how
you can implement a using @code{call-with-ssh-forward}:

@lisp
(let ((pid (primitive-fork)))
  (if (zero? pid)
      ;; Make a new SSH session, connect it and authenticate the user.
      (let* ((host    "example.org")
             (user    "alice")
             (session (make-session #:user user
                                    #:host host
                                    #:port 22
                                    #:log-verbosity 'nolog)))
        (connect! session)
        (userauth-agent! session)
        ;; Make a new SSH tunnel.
        (let ((tunnel (make-tunnel session
                                   #:port 12345
                                   ;; Guile-RPC server listens on 127.0.0.1
                                   ;; on the remote host.
                                   #:host "127.0.0.1"
                                   ;; Guile-RPC server port.
                                   #:host-port 6666)))
          ;; Start the forwarder loop.
          (start-forward tunnel)))
      ;; Parent process.
      (let ((sock (socket PF_INET SOCK_STREAM 0)))
      (dynamic-wind
        (const #t)
        (lambda ()
          (sleep 1)
          ;; Connect to the port that is listened to by the spawned process.
          (connect sock AF_INET
            (inet-pton AF_INET "127.0.0.1")
            12345)

          ;; Make an RPC call using the SSH tunnel.
          (display (invoke-split-number 3.14 #x7777 sock))
          (newline))
        (lambda ()
          (close sock)
          (kill pid SIGTERM)
          (waitpid pid))))))
@end lisp

The full example of an RPC client that uses a SSH tunnel is in
@file{$prefix/share/guile-ssh/examples/rpc} directory.
@end deffn

@c -----------------------------------------------------------------------------
@subsection Example

Here is a simple Guile program that connects to ``www.example.org'' and starts
port forwading from the local port 8080 to the port 80 on the remote host:

@lisp
#!/usr/bin/guile \
-e main
!#

(use-modules (ssh session)
             (ssh auth)
             (ssh key)
             (ssh tunnel))

(define (main args)
  (let ((s (make-session #:user          "alice"
                         #:host          "localhost"
                         #:port          22
                         #:log-verbosity 'nolog))
        (k (private-key-from-file "/home/alice/.ssh/id_rsa")))
    (connect! s)
    (userauth-public-key! s k)
    (let ((t (make-tunnel s
                          #:port      8080
                          #:host      "www.example.org"
                          #:host-port 80)))
      (start-forward t))))
@end lisp

@c Local Variables:
@c TeX-master: "guile-ssh.texi"
@c End:
