1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
|
@c -*-texinfo-*-
@c This file is part of Guile-SSH Reference Manual.
@c Copyright (C) 2014 Artyom V. Poptsov
@c See the file guile-ssh.texi for copying conditions.
@node Channels
@section Channels
@menu
* Channel Management::
* Port Forwarding::
* Tunnels::
@end menu
@node Channel Management
@subsection Channel Management
@cindex data transferring
@tindex channel
The @code{(ssh channel)} module provides facilities to create
Guile-SSH channels and manipulating of them.
Channels are implemented as GNU Guile ports. Therefore they can be
used with regular I/O procedures such as @code{display}, @code{write},
@code{read-line} and friends (@pxref{Input and Output,,, guile, The
GNU Guile Reference Manual}). This section describes operations that
are specific for the channels.
@deffn {Scheme Procedure} channel? x
Return @code{#t} if @var{x} is a Guile-SSH channel, @code{#f}
otherwise.
@end deffn
@deffn {Scheme Procedure} make-channel session [mode]
Allocate a new Guile-SSH channel for the @var{session} (@pxref{Sessions}).
@var{flags} are determine what kind of a channel should be created. Possible
modes are: @code{OPEN_READ}, @code{OPEN_WRITE}, @code{OPEN_BOTH}. They allow
to create either an input channel, output channel or input/output channel
respectively.
@end deffn
@deffn {Scheme Procedure} channel-open-session channel
Open a session channel. This procedure actually turn the
@var{channel} into an open port available for I/O operations. Throw
@code{guile-ssh-error} on error. Return value is undefined.
@end deffn
@deffn {Scheme Procedure} channel-request-exec channel command
@cindex non-interactive SSH session
@cindex command execution
Run a shell @var{command} without an interactive shell. The @var{channel}
must be open. Throw @code{guile-ssh-error} on error. Return value is
undefined.
@strong{Note} that the procedure only can be used to execute a single command
on the remote host, so you should close the channel after
@code{channel-request-exec}. If you want to execute another command then you
must open a new channel and use it.
Example:
@lisp
(let ((channel (make-channel session)))
(channel-open-session channel)
(channel-request-exec channel "uname")
(read-line channel))
@result{} "Linux"
@end lisp
@end deffn
@deffn {Scheme Procedure} channel-request-pty channel
Request a @acronym{PTY} (pseudo terminal). Throw @code{guile-ssh-error} on
error. The @var{channel} must be open. Return value is undefined.
@end deffn
@deffn {Scheme Procedure} channel-request-shell channel
Request a shell. The @var{channel} must be open. Throw
@code{guile-ssh-error} on error. Return value is undefined.
@end deffn
@deffn {Scheme Procedure} channel-request-env channel variable value
@cindex setting of environment variables
Set an environment @var{variable} to @var{value}. Throw
@code{guile-ssh-error} on error. The @var{channel} must be open. Return
value is undefined.
@end deffn
@deffn {Scheme Procedure} channel-request-send-exit-status channel exit-status
Send an @var{exit-status} to the remote process (as described in RFC 4254,
section 6.10). Only SSH-v2 is supported. Return value is undefined.
The @var{channel} needs to be closed with after this message.
@end deffn
@deffn {Scheme Procedure} channel-set-pty-size! channel columns rows
Change size of the @acronym{PTY} to @var{columns} and @var{rows}. The
@var{channel} must be open. Return value is undefined.
@end deffn
@deffn {Scheme Procedure} channel-set-stream! channel stream
Set default @var{stream} for @var{channel}. @var{stream} must be one of the
following symbols: @code{stdout} (default), @code{stderr}. The @var{channel}
must be open. Throw @code{guile-ssh-error} on error. Return value is
undefined.
Example:
@lisp
(channel-set-stream! channel 'stderr)
@end lisp
@end deffn
@deffn {Scheme Procedure} channel-get-stream channel
Get current stream name from @var{channel}. The @var{channel} must be open.
Throw @code{guile-ssh-error} on error. Return one of the following symbols:
@code{stdout}, @code{stderr}.
Example:
@lisp
(channel-get-stream channel)
@result{} 'stderr
@end lisp
@end deffn
@deffn {Scheme Procedure} channel-get-session channel
Get the session to which belongs the @var{channel}. Throw
@code{guile-ssh-error} on an error. Return the session.
@end deffn
@deffn {Scheme Procedure} channel-eof? channel
Return @code{#t} if remote has sent @acronym{EOF}, @code{#f} otherwise. Throw
@code{guile-ssh-error} if the channel has been closed and freed.
@end deffn
@deffn {Scheme Procedure} channel-get-exit-status channel
Get the exit status of the @var{channel} (error code from the executed
instruction). The @var{channel} must be open. Return the exist status, or
@code{#f} if no exit status has been returned (yet). Throw
@code{guile-ssh-error} on error.
@end deffn
@node Port Forwarding
@subsection Port Forwarding
@cindex Port forwarding
Low-level API from @code{(ssh channel)} module to manage SSH port
forwarding. These procedures @strong{do not} bind the ports and do not
automatically forward the content of a socket to the channel. You should
either implement binding and data forwarding in your application or use the
tunnel API (@pxref{Tunnels, Guile-SSH tunnel API})
@deffn {Scheme Procedure} channel-open-forward channel [#:source-host=''localhost''] #:local-port #:remote-host [#:remote-port=local-port]
Open a (local) TCP/IP forwarding @var{channel}. Connect to a
@var{remote-host} and @var{remote-port}, and use @var{source-host} and
@var{local-port} as origination of connections.
The procedure returns one of the following symbols:
@table @samp
@item ok
Success.
@item again
We are in the nonblocking mode and the call to be done again.
@item error
An error occured.
@end table
The local port forwarding works as follows:
@example
local-host remote-host
,..............., ,.................
: : : :
: [a browser] : : [a web server] :
: | : : A :
: | : : | :
: port 8080 : : port 80 :
: | : : | :
: V : : | :
: [SSH client]===========>[SSH server] :
: : : :
'...............' '................'
@end example
Where port 8080 is an arbitrary @var{local-port} and port 80 is a
@var{remote-port}.
Also in our case, ``SSH client'' is an application that uses Guile-SSH and
calls @code{channel-open-forward}.
Example:
@lisp
(channel-open-forward channel
#:local-port 8080
#:remote-host "www.example.org"
#:remote-port 80)
@end lisp
@end deffn
@deffn {Scheme Procedure} channel-listen-forward session [#:address=#f] [#:port=0]
Start a TCP/IP reverse (remote) port forwarding. Send the ``tcpip-forward''
global request using @var{session} to ask the server to begin listening for
inbound connections on the specified @var{address} and @var{port}.
If @var{address} is not specified (or set to @code{#f}) then the server binds
all addresses on all protocol families supported by the server. When 0 is
passed as a @var{port} then server allocates the next unprivileged port.
The procedure returns two values: the first value is the result of the
operation, and the second value is the bound port number; if @var{port} was
set to 0 then the procedure returns the chosen port number.
The result of the operation can be one of the following symbols:
@table @samp
@item ok
Success.
@item again
We are in the nonblocking mode and the call to be done again.
@item error
An error occured.
@end table
Reverse port forwarding looks as follows:
@example
local-host remote-host
,................, ,.................
: : : :
: [a web server] : : [a browser] :
: A : : | :
: | : : | :
: port 80 : : port 8080 :
: | : : | :
: | : : V :
: [SSH client]<===========[SSH server] :
: : : :
'................' '................'
@end example
@end deffn
@deffn {Scheme Procedure} channel-accept-forward session [timeout=0]
Accept an incoming TCP/IP forwarding channel and get information about
incoming connection. Return two values: the first value is the incoming
channel, and the second value is a port number on which the connection was
issued.
@end deffn
@deffn {Scheme Procedure} channel-cancel-forward session address port
Send ``cancel-tcpip-forward'' global request to @var{session} to ask the
server to cancel a ``tcpip-forward'' request on the bound @var{address} and
@var{port}.
The result of the operation can be one of the following symbols:
@table @samp
@item ok
Success.
@item again
We are in the nonblocking mode and the call to be done again.
@item error
An error occured.
@end table
Here's an example Guile program that uses @code{channel-cancel-forward} to
cancel reverse port forwarding on a server:
@lisp
#!/usr/bin/guile \
-e main
!#
(use-modules (ssh session)
(ssh auth)
(ssh channel))
(define (main args)
(let ((session (make-session #:user "alice"
#:host "127.0.0.1"
#:port 22
#:log-verbosity 'rare)))
(connect! session)
(userauth-agent! session)
;; Send "tcpip-forward" request to an SSH server
(channel-listen-forward session #:address "localhost" #:port 12345)
;; Accept incoming reverse port forwarding requests with
;; 'channel-accept-forward' in some kind of loop...
;; Cancel the issued "tcpip-forward" request with
;; "cancel-tcpip-forward" request
(channel-cancel-forward session "localhost" 12345)))
@end lisp
@end deffn
@node Tunnels
@subsection 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
a socket as an argument. All I/O on the socket 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 an RPC call using @code{call-with-ssh-forward}:
@lisp
(let ((t (make-tunnel session
#:port 12345
;; Suppose a Guile-RPC server listens on
;; 127.0.0.1:23456 on the remote host:
#:host "127.0.0.1"
#:host-port 23456)))
(call-with-ssh-forward t
(lambda (socket)
(RPC-PROGRAM-proc some-data #x123 socket))))
@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
@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:
|