Prepare for sandboxing the xmppipe process by adding a function called
after all file descriptors are allocated.
The intent of the sandbox is to limit the xmppipe process to the role
of a component in a shell pipeline: reading from stdin, reading/writing
to the XMPP socket and writing to stdout. Any activity not involved with
using stdio should force the process to exit.
The sandbox function will vary based on the capabilities of the
platform. The default sandbox function does nothing.
Limitations of the sandbox:
Probably the biggest risk is in session establishment:
* the TLS handshake
* the XML parsing
The sandbox is enforced after the TLS connection is established, i.e.,
after the file descriptor for the XMPP session is allocated and so has no
effect on the TLS handshake or the initial XMPP handshake.
Possibly an initial sandbox could be setup for the connection phase
followed by a stricter sandbox for the stdio phase.
Use uuid_create(3) and uuid_to_string(3) to create the message id on
BSDs. Only tested on FreeBSD but should work on OpenBSD and NetBSD.
Add untested support for compiling on Solaris and Mac OS X:
* SmartOS has libuuid installed by default with rsyslog via pkgsrc
* Mac OS X has libuuid as part of libSystem:
http://lists.apple.com/archives/unix-porting/2009/Aug/msg00006.html
Lengthen the poll delay to read in larger chunks of data. With a poll
value of 1 ms, there could be a large protocol message overhead: 1
character per XML stanza.
Server (system with access to the SSH and XMPP server):
# ssh-over-xmpp server <conference> <IP address> <port>
ssh-over-xmpp server sshxmpp 1.2.3.4 22
Client (system with access to the XMPP server):
ssh -o ProxyCommand="ssh-over-xmpp client sshxmpp" 127.0.0.1
Use a fixed ping handler rather than scheduling a ping handler per ping
request.
If the XMPP client or server is busy, many outstanding ping requests
can be waiting, resulting in a number of ping handlers being queued.
Each of the ping handlers does the same thing (resets the failure count
to 0) but any dropped pings resulted in the handlers being queued
forever.
For ejabberd and the mongooseim fork of ejabbered, 4097 bytes is around
the maximum message size before messages are dropped (the extra byte is
for libstrophe to put the terminating NULL. Otherwise, with a buffer
of 4096, the message will be broken up into 2 parts, with the second
consisting of the last byte of the message).
With base64 encoding, the message size will increase to 4097 * 4 / 3
bytes. When sending streams of binary data (cat'ing a file over XMPP,
ssh over XMPP, ...), stream management will get backlogged and messages
will disappear.
So halve the default buffer size. Is it too big for other jabber
servers? It is one of the mysteries but the "-b" option exists for those.
Implement flow control by monitoring the number of unacked stream
requests and the number of unprocessed stanzas. If either exceeds a user
controlled limit, xmppipe will stop reading from stdin. Further stream
requests will be generated whenever the keepalive timeout is reached and
an XMPP ping is sent.
ejabberd/mongooseim will close the connection if there are about 5
unacked stream requests. xmppipe should probably do the same thing.
With these changes, binaries can be reliably (but slowly) sent over
XMPP. ssh over XMPP is also working reliably (with light testing). Because
of the increase in size due to base64 encoding, the buffer size needs
to be reduced so the encoded message is under 4k (-m 1024 is ok).
When stdin is closed with stream management enabled, xmppipe waits for
the ack to match the number of stanzas sent to ensure all the data has
been flushed to the server.
The server may not respond to every stream request and a stream request
message is generated only when a stanza is sent. Since stdin is closed,
the only traffic is the XMPP pings which are sent out every 60 seconds
by default. The result is, when stdin is closed, it may take several
minutes for xmppipe to exit.
Work around the problem by sending a stream management request for every
stanza.
Optionally base64 encode data sent to and from a conference, allowing
transfer of binary data.
This could also be accomplished by piping in base64 encoded data:
base64 /bin/ls | xmppipe
However the base64 command does not work with streams of data.
Check for errors on libstrophe functions that return non-void. Some of
the funs have undocumented failure conditions (e.g.,
xmpp_stanza_copy()). Others return less than zero or enum values. To
account for future discoveries, use a wrapper instead of a macro.
Request stream management for the session by default. The rate of requests
and acks is controlled by the -I option. With stream management, the
client can check when all stanzas have been flushed to the server. For
example, the following works:
cat /path/textfile | xmppipe -o transfer -r sender
# on another system
xmppipe -o transfer -r receiver > tmpfile
The behaviour is to always attempt enabling stream management. The XEP
is ambiguous about the response to an enable when stream management is
not offered. Presumably the server will respond with "failure".
So the code should probably have 2 checks:
* if stream management is offered as a feature, send an enable
* if the server responds with "enabled", handle requests
Set a limit on the number of pings without a reply and exit if the limit
is reached. Useful for detecing broken network connections due to
network changes.
The default configuration will take about 4 minutes to detect failure
(1 keepalive every 60 seconds, tolerate 3 failures).