2
0
mirror of https://github.com/msantos/xmppipe synced 2024-11-16 00:12:59 +00:00
Commit Graph

46 Commits

Author SHA1 Message Date
Michael Santos
c17b196053 sandbox: add a pre-connect sandbox
Add a sandbox enforced before options are parsed and the connection is
established to the XMPP server. This sandbox will allow network
operations.

The post-connect sandbox is unchanged and restricts operations to stdio.

The commit just adds the infrastructure for the pre-connect sandbox.
2017-04-10 11:25:01 -04:00
Michael Santos
be90386d6e stream management: check h value in server response 2017-03-19 09:44:59 -04:00
Michael Santos
f4d9184bac Add wrapper around strtonum(3) for options 2017-03-18 08:00:59 -04:00
Michael Santos
cee9094fc8 options: use strtonum(3) to convert numbers
Limit the ranges for integers accepted as command line options.
2017-03-17 08:13:23 -04:00
Michael Santos
f30f666d87 Convert last handled stanza using strtonum(3) 2017-03-05 09:21:58 -05:00
Michael Santos
58cb075664 state: set room name/resource before options 2017-02-26 14:51:44 -05:00
Michael Santos
ad56bab3cc xmppipe_roomname: use define for hostname 2017-02-25 09:18:04 -05:00
Michael Santos
f51377428f Ignore invalid base64 messages
When base64 encoding is enabled, ignore any messages that fail base64
decoding.

Previously signed-unsigned integer conversion would cause the return
value of b64_pton() on error (a negative integer) to be converted to a
large value. The attempt to allocate this value would force xmppipe to
exit.
2017-02-13 10:07:06 -05:00
Michael Santos
7f0b5863c0 handle_stdin: use fd for nfds 2017-02-10 10:18:01 -05:00
Michael Santos
25f3441b33 README: add information about sandbox 2017-02-06 10:03:06 -05:00
Michael Santos
707d7cf19d Display enforced sandbox in verbose mode 2017-02-03 09:47:12 -05:00
Michael Santos
a34d5766c5 sandbox: basic rlimit sandbox
The rlimit sandbox disables forking processes and opening files.

The rlimit sandbox is not used by default yet. To compile it:

    XMPPIPE_SANDBOX=XMPPIPE_SANDBOX_RLIMIT make

The rlimit sandbox should work on any platform. However the interaction
of RLIMIT_NOFILE with poll(2) (and select(2)?) on some platforms (FreeBSD
but really any OS besides Linux) is problematic:

* opening a number of fd's, setting RLIMIT_NOFILE to 0, calling
  poll(2) on the fdset

  Linux: works
  FreeBSD: fails

* opening a number of fd's, setting RLIMIT_NOFILE to maxfd+1, calling
  poll(2) on the fdset

  Linux: works
  FreeBSD: works

The issue with the second option is that a library may have opened a
sequence of file descriptors then closed the lower numbered fd's:

    open() => 3
    open() => 4
    open() => 5
    close(3)
    close(4)
    maxfd = 5

RLIMIT_NOFILE would be set to 6 (stdin, stdout, stderr, 3, 4, 5) and the
sandbox would allow re-opening fd's 3 and 4.

One possible fix would be to run through the sequence of fd's before
entering the rlimit sandbox:

* test if the fd is closed
* if the fd is closed, dup2(STDIN_FILENO, fd)

Since the closed fd's are not part of the pollset, they will not be
polled and should be ignored.

Note we can't simply move maxfd to the lowest unused fd because
libstrophe maintains the fd number as internal, opaque state.

Empirically, the xmpp fd is always 3. Another option would be to abort
the process if the fd does not equal 3.
2017-01-31 08:17:02 -05:00
Michael Santos
a7d0ca7e47 Initial support for sandboxing
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.
2017-01-29 09:44:12 -05:00
Michael Santos
e20bca9bd1 const'ify all the things 2017-01-18 06:31:24 -05:00
Michael Santos
550eaf4e59 Check message id has been allocated 2016-10-28 10:14:40 -04:00
Michael Santos
04c05bd5f2 xmppipe: avoid memory leak from duplicate options 2016-10-08 11:10:15 -04:00
Michael Santos
2f2805d68a stdin: combine read error check 2016-09-09 06:57:49 -04:00
Michael Santos
16f03deff4 Fix typo 2016-09-07 10:22:58 -04:00
Michael Santos
877ecd5619 Flush stdout after print 2016-09-06 08:15:25 -04:00
Michael Santos
fc09ca4ff1 Be explicit with checks 2015-07-21 09:44:08 -04:00
Michael Santos
a392e836a0 Compile on BSDs
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
2015-07-01 09:31:44 -04:00
Michael Santos
c814208bad Remove check for negative unsigned integer O.o 2015-06-30 12:19:20 -04:00
Michael Santos
69f97cd872 Add "to" field to message
Distinguish which user received a message. Possibly useful if multiple
sessions are logged in or someone directly messages the bot.
2015-06-29 10:29:44 -04:00
Michael Santos
4310fe0e6b Exit when disconnected 2015-06-28 10:34:41 -04:00
Michael Santos
e82fc91bfb xmpp_stanza_get_name: check for NULL 2015-06-11 09:55:54 -04:00
Michael Santos
37bd93160b Reset ping failures after any response
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.
2015-06-10 07:49:21 -04:00
Michael Santos
c3c83f9d72 Lower the default buffer size
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.
2015-06-03 10:08:37 -04:00
Michael Santos
1975057b6d -m -> -b
Rename the buffer size switch to something more memorable. Add a missing
break in the option processing switch statement.
2015-06-02 08:17:28 -04:00
Michael Santos
4c69352f19 stream management: flow control
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).
2015-06-01 09:39:22 -04:00
Michael Santos
5c14db6448 sm: request ack for every stanza
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.
2015-05-31 08:56:04 -04:00
Michael Santos
147e0d7c2b Consistenly check xmpp get ops for NULL values 2015-05-30 10:41:36 -04:00
Michael Santos
16ec036134 Fix format warnings 2015-05-26 07:43:45 -04:00
Michael Santos
3ae0a9f88f Transparently base64 encode data to MUC
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.
2015-05-24 10:27:59 -04:00
Michael Santos
bcf7c1b2e8 Check libstrophe funs for NULL return values
Ensure XML elements may exist in the stanza before attempting to use
them.
2015-05-23 09:06:24 -04:00
Michael Santos
4cbd8ec1c3 Add wrappers around libstrophe funs that may fail
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.
2015-05-22 09:48:15 -04:00
Michael Santos
ef7e414af6 Exit on connection failure
Should output a better error message based on the status returned to
handle_connection.
2015-05-21 10:11:22 -04:00
Michael Santos
cf501f5fde Optionally disable XMPP pings 2015-05-19 08:03:02 -04:00
Michael Santos
fdab8a8901 Initial support for XEP-0198 stream management
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
2015-05-18 09:27:47 -04:00
Michael Santos
a233caf32c Set default keepalive failure limit 2015-05-16 11:10:31 -04:00
Michael Santos
246c148d0e Track ping replies
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).
2015-05-16 10:58:20 -04:00
Michael Santos
4cbee9c78c Optionally specify server address/port 2015-05-16 09:54:35 -04:00
Michael Santos
c983814007 Exit on connection failure
No point shutting down nicely if the connection has failed: exit
immediately and print out an error.

The error is the same whether the connection has failed due to a DNS
lookup, TCP connection or authentication failure. Running in debug mode
can show the reason for failure. libstrophe has an enum indicating the
connection state; maybe this can be used for better error reporting.
2015-05-15 10:00:38 -04:00
Michael Santos
353951298e Generate a unique ID per message
Add a ID per message. Seems to fix the duplicate messages seen with MUCs
on the Conversations android client whenever the network is switched
(e.g., from wifi to cell).

Introduce a dependency on Linux's libuuid which introduces portability
issues. However, it should be simple to add support for the BSD UUID
interface.

libuuid was used because it is a fast and simple way of generating
a unique id.  Realistically, the ID only needs to be unique within
the MUC and so could probably be replaced with an sprintf() combining
time of day, PID and a random number.
2015-05-14 06:56:58 -04:00
Michael Santos
4325445536 Exit on presence errors
Force exiting on nick conflicts. xmppipe could generate a unique resource
(e.g., xmppipe-<pid>) but it prevents accidentally having two instances
running in a room.
2015-05-13 07:37:34 -04:00
Michael Santos
849507ad5d mucxxx -> muc_xxx; ERR -> XMPPIPE_ERR 2015-05-12 14:09:14 -04:00
Michael Santos
3d79e9fda8 Forward stdin over XMPP 2015-05-11 15:19:35 -04:00