source: protocols/jabber/s5bytestream.c @ 0b9daac

Last change on this file since 0b9daac was 0b9daac, checked in by dequis <dx@…>, at 2015-02-20T23:16:08Z

Reorganize include files to avoid conflicts with other libs

  • Change all header includes to be relative to the project root
  • Remove -I${includedir} from bitlbee.pc Cflags
  • Install lib and protocols headers to their own directories. So now it is:

/usr/include/bitlbee/*.h
/usr/include/bitlbee/lib/*.h
/usr/include/bitlbee/protocols/*.h

This breaks backwards compatibility of third party plugins, but now
they don't have to do ambiguous includes like #include <proxy.h>

This also fixes trac ticket 1170 - conflicts when libproxy and liboauth
are installed at the same time bitlbee is built, which the macports
project ran into several times.

  • Property mode set to 100644
File size: 32.7 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - SOCKS5 Bytestreams ( XEP-0065 )                          *
5*                                                                           *
6*  Copyright 2007 Uli Meis <a.sporto+bee@gmail.com>                         *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
25#include "lib/sha1.h"
26#include "lib/ftutil.h"
27#include <poll.h>
28
29struct bs_transfer {
30
31        struct jabber_transfer *tf;
32
33        jabber_streamhost_t *sh;
34        GSList *streamhosts;
35
36        enum {
37                BS_PHASE_CONNECT,
38                BS_PHASE_CONNECTED,
39                BS_PHASE_REQUEST,
40                BS_PHASE_REPLY
41        } phase;
42
43        /* SHA1( SID + Initiator JID + Target JID) */
44        char *pseudoadr;
45
46        gint connect_timeout;
47
48        char peek_buf[64];
49        int peek_buf_len;
50};
51
52struct socks5_message {
53        unsigned char ver;
54        union {
55                unsigned char cmd;
56                unsigned char rep;
57        } cmdrep;
58        unsigned char rsv;
59        unsigned char atyp;
60        unsigned char addrlen;
61        unsigned char address[40];
62        in_port_t port;
63} __attribute__ ((packed));
64
65char *socks5_reply_code[] = {
66        "succeeded",
67        "general SOCKS server failure",
68        "connection not allowed by ruleset",
69        "Network unreachable",
70        "Host unreachable",
71        "Connection refused",
72        "TTL expired",
73        "Command not supported",
74        "Address type not supported",
75        "unassigned"
76};
77
78/* connect() timeout in seconds. */
79#define JABBER_BS_CONTIMEOUT 15
80/* listen timeout */
81#define JABBER_BS_LISTEN_TIMEOUT  90
82
83/* very useful */
84#define ASSERTSOCKOP(op, msg) \
85        if ((op) == -1) { \
86                return jabber_bs_abort(bt, msg ": %s", strerror(errno)); }
87
88gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...);
89void jabber_bs_canceled(file_transfer_t *ft, char *reason);
90void jabber_bs_free_transfer(file_transfer_t *ft);
91gboolean jabber_bs_connect_timeout(gpointer data, gint fd, b_input_condition cond);
92gboolean jabber_bs_poll(struct bs_transfer *bt, int fd, short *revents);
93gboolean jabber_bs_peek(struct bs_transfer *bt, void *buffer, int buflen);
94
95void jabber_bs_recv_answer_request(struct bs_transfer *bt);
96gboolean jabber_bs_recv_read(gpointer data, gint fd, b_input_condition cond);
97gboolean jabber_bs_recv_write_request(file_transfer_t *ft);
98gboolean jabber_bs_recv_handshake(gpointer data, gint fd, b_input_condition cond);
99gboolean jabber_bs_recv_handshake_abort(struct bs_transfer *bt, char *error);
100int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
101
102gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error);
103gboolean jabber_bs_send_request(struct jabber_transfer *tf, GSList *streamhosts);
104gboolean jabber_bs_send_handshake(gpointer data, gint fd, b_input_condition cond);
105static xt_status jabber_bs_send_handle_activate(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
106void jabber_bs_send_activate(struct bs_transfer *bt);
107
108/*
109 * Frees a bs_transfer struct and calls the SI free function
110 */
111void jabber_bs_free_transfer(file_transfer_t *ft)
112{
113        struct jabber_transfer *tf = ft->data;
114        struct bs_transfer *bt = tf->streamhandle;
115        jabber_streamhost_t *sh;
116
117        if (bt->connect_timeout) {
118                b_event_remove(bt->connect_timeout);
119                bt->connect_timeout = 0;
120        }
121
122        if (tf->watch_in) {
123                b_event_remove(tf->watch_in);
124                tf->watch_in = 0;
125        }
126
127        if (tf->watch_out) {
128                b_event_remove(tf->watch_out);
129                tf->watch_out = 0;
130        }
131
132        g_free(bt->pseudoadr);
133
134        while (bt->streamhosts) {
135                sh = bt->streamhosts->data;
136                bt->streamhosts = g_slist_remove(bt->streamhosts, sh);
137                g_free(sh->jid);
138                g_free(sh->host);
139                g_free(sh);
140        }
141
142        g_free(bt);
143
144        jabber_si_free_transfer(ft);
145}
146
147/*
148 * Checks if buflen data is available on the socket and
149 * writes it to buffer if that's the case.
150 */
151gboolean jabber_bs_peek(struct bs_transfer *bt, void *buffer, int buflen)
152{
153        int ret;
154        int fd = bt->tf->fd;
155
156        if (buflen > sizeof(bt->peek_buf)) {
157                return jabber_bs_abort(bt, "BUG: %d > sizeof(peek_buf)", buflen);
158        }
159
160        ASSERTSOCKOP(ret = recv(fd, bt->peek_buf + bt->peek_buf_len,
161                                buflen - bt->peek_buf_len, 0), "recv() on SOCKS5 connection");
162
163        if (ret == 0) {
164                return jabber_bs_abort(bt, "Remote end closed connection");
165        }
166
167        bt->peek_buf_len += ret;
168        memcpy(buffer, bt->peek_buf, bt->peek_buf_len);
169
170        if (bt->peek_buf_len == buflen) {
171                /* If we have everything the caller wanted, reset the peek buffer. */
172                bt->peek_buf_len = 0;
173                return buflen;
174        } else {
175                return bt->peek_buf_len;
176        }
177}
178
179
180/*
181 * This function is scheduled in bs_handshake via b_timeout_add after a (non-blocking) connect().
182 */
183gboolean jabber_bs_connect_timeout(gpointer data, gint fd, b_input_condition cond)
184{
185        struct bs_transfer *bt = data;
186
187        bt->connect_timeout = 0;
188
189        jabber_bs_abort(bt, "no connection after %d seconds",
190                        bt->tf->ft->sending ? JABBER_BS_LISTEN_TIMEOUT : JABBER_BS_CONTIMEOUT);
191
192        return FALSE;
193}
194
195/*
196 * Polls the socket, checks for errors and removes a connect timer
197 * if there is one.
198 */
199gboolean jabber_bs_poll(struct bs_transfer *bt, int fd, short *revents)
200{
201        struct pollfd pfd = { .fd = fd, .events = POLLHUP | POLLERR };
202
203        if (bt->connect_timeout) {
204                b_event_remove(bt->connect_timeout);
205                bt->connect_timeout = 0;
206        }
207
208        ASSERTSOCKOP(poll(&pfd, 1, 0), "poll()")
209
210        if (pfd.revents & POLLERR) {
211                int sockerror;
212                socklen_t errlen = sizeof(sockerror);
213
214                if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen)) {
215                        return jabber_bs_abort(bt,
216                                               "getsockopt() failed, unknown socket error during SOCKS5 handshake (weird!)");
217                }
218
219                if (bt->phase == BS_PHASE_CONNECTED) {
220                        return jabber_bs_abort(bt, "connect failed: %s", strerror(sockerror));
221                }
222
223                return jabber_bs_abort(bt, "Socket error during SOCKS5 handshake(weird!): %s", strerror(sockerror));
224        }
225
226        if (pfd.revents & POLLHUP) {
227                return jabber_bs_abort(bt, "Remote end closed connection");
228        }
229
230        *revents = pfd.revents;
231
232        return TRUE;
233}
234
235/*
236 * Used for receive and send path.
237 */
238gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...)
239{
240        va_list params;
241
242        va_start(params, format);
243        char error[128];
244
245        if (vsnprintf(error, 128, format, params) < 0) {
246                sprintf(error, "internal error parsing error string (BUG)");
247        }
248        va_end(params);
249        if (bt->tf->ft->sending) {
250                return jabber_bs_send_handshake_abort(bt, error);
251        } else {
252                return jabber_bs_recv_handshake_abort(bt, error);
253        }
254}
255
256/* Bad luck */
257void jabber_bs_canceled(file_transfer_t *ft, char *reason)
258{
259        struct jabber_transfer *tf = ft->data;
260
261        imcb_log(tf->ic, "File transfer aborted: %s", reason);
262}
263
264/*
265 * Parses an incoming bytestream request and calls jabber_bs_handshake on success.
266 */
267int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode)
268{
269        char *sid, *ini_jid, *tgt_jid, *mode, *iq_id;
270        struct jabber_data *jd = ic->proto_data;
271        struct jabber_transfer *tf = NULL;
272        GSList *tflist;
273        struct bs_transfer *bt;
274        GSList *shlist = NULL;
275        struct xt_node *shnode;
276
277        sha1_state_t sha;
278        char hash_hex[41];
279        unsigned char hash[20];
280        int i;
281
282        if (!(iq_id   = xt_find_attr(node, "id")) ||
283            !(ini_jid = xt_find_attr(node, "from")) ||
284            !(tgt_jid = xt_find_attr(node, "to")) ||
285            !(sid     = xt_find_attr(qnode, "sid"))) {
286                imcb_log(ic, "WARNING: Received incomplete SI bytestream request");
287                return XT_HANDLED;
288        }
289
290        if ((mode = xt_find_attr(qnode, "mode")) &&
291            (strcmp(mode, "tcp") != 0)) {
292                imcb_log(ic, "WARNING: Received SI Request for unsupported bytestream mode %s",
293                         xt_find_attr(qnode, "mode"));
294                return XT_HANDLED;
295        }
296
297        shnode = qnode->children;
298        while ((shnode = xt_find_node(shnode, "streamhost"))) {
299                char *jid, *host, *port_s;
300                int port;
301                if ((jid = xt_find_attr(shnode, "jid")) &&
302                    (host = xt_find_attr(shnode, "host")) &&
303                    (port_s = xt_find_attr(shnode, "port")) &&
304                    (sscanf(port_s, "%d", &port) == 1)) {
305                        jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
306                        sh->jid = g_strdup(jid);
307                        sh->host = g_strdup(host);
308                        sprintf(sh->port, "%u", port);
309                        shlist = g_slist_append(shlist, sh);
310                }
311                shnode = shnode->next;
312        }
313
314        if (!shlist) {
315                imcb_log(ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries");
316                return XT_HANDLED;
317        }
318
319        /* Let's see if we can find out what this bytestream should be for... */
320
321        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
322                struct jabber_transfer *tft = tflist->data;
323                if ((strcmp(tft->sid, sid) == 0) &&
324                    (strcmp(tft->ini_jid, ini_jid) == 0) &&
325                    (strcmp(tft->tgt_jid, tgt_jid) == 0)) {
326                        tf = tft;
327                        break;
328                }
329        }
330
331        if (!tf) {
332                imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
333                return XT_HANDLED;
334        }
335
336        /* iq_id and canceled can be reused since SI is done */
337        g_free(tf->iq_id);
338        tf->iq_id = g_strdup(iq_id);
339
340        tf->ft->canceled = jabber_bs_canceled;
341
342        /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
343        sha1_init(&sha);
344        sha1_append(&sha, (unsigned char *) sid, strlen(sid));
345        sha1_append(&sha, (unsigned char *) ini_jid, strlen(ini_jid));
346        sha1_append(&sha, (unsigned char *) tgt_jid, strlen(tgt_jid));
347        sha1_finish(&sha, hash);
348
349        for (i = 0; i < 20; i++) {
350                sprintf(hash_hex + i * 2, "%02x", hash[i]);
351        }
352
353        bt = g_new0(struct bs_transfer, 1);
354        bt->tf = tf;
355        bt->streamhosts = shlist;
356        bt->sh = shlist->data;
357        bt->phase = BS_PHASE_CONNECT;
358        bt->pseudoadr = g_strdup(hash_hex);
359        tf->streamhandle = bt;
360        tf->ft->free = jabber_bs_free_transfer;
361
362        jabber_bs_recv_handshake(bt, -1, 0);
363
364        return XT_HANDLED;
365}
366
367/*
368 * This is what a protocol handshake can look like in cooperative multitasking :)
369 * Might be confusing at first because it's called from different places and is recursing.
370 * (places being the event thread, bs_request, bs_handshake_abort, and itself)
371 *
372 * All in all, it turned out quite nice :)
373 */
374gboolean jabber_bs_recv_handshake(gpointer data, gint fd, b_input_condition cond)
375{
376
377        struct bs_transfer *bt = data;
378        short revents;
379        int gret;
380
381        if ((fd != -1) && !jabber_bs_poll(bt, fd, &revents)) {
382                return FALSE;
383        }
384
385        switch (bt->phase) {
386        case BS_PHASE_CONNECT:
387        {
388                struct addrinfo hints, *rp;
389
390                memset(&hints, 0, sizeof(struct addrinfo));
391                hints.ai_socktype = SOCK_STREAM;
392
393                if ((gret = getaddrinfo(bt->sh->host, bt->sh->port, &hints, &rp)) != 0) {
394                        return jabber_bs_abort(bt, "getaddrinfo() failed: %s", gai_strerror(gret));
395                }
396
397                ASSERTSOCKOP(bt->tf->fd = fd = socket(rp->ai_family, rp->ai_socktype, 0), "Opening socket");
398
399                sock_make_nonblocking(fd);
400
401                imcb_log(bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host,
402                         bt->sh->port);
403
404                if ((connect(fd, rp->ai_addr, rp->ai_addrlen) == -1) &&
405                    (errno != EINPROGRESS)) {
406                        return jabber_bs_abort(bt, "connect() failed: %s", strerror(errno));
407                }
408
409                freeaddrinfo(rp);
410
411                bt->phase = BS_PHASE_CONNECTED;
412
413                bt->tf->watch_out = b_input_add(fd, B_EV_IO_WRITE, jabber_bs_recv_handshake, bt);
414
415                /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
416                bt->connect_timeout = b_timeout_add(JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt);
417
418                bt->tf->watch_in = 0;
419                return FALSE;
420        }
421        case BS_PHASE_CONNECTED:
422        {
423                struct {
424                        unsigned char ver;
425                        unsigned char nmethods;
426                        unsigned char method;
427                } socks5_hello = {
428                        .ver = 5,
429                        .nmethods = 1,
430                        .method = 0x00         /* no auth */
431                                  /* one could also implement username/password. If you know
432                                   * a jabber client or proxy that actually does it, tell me.
433                                   */
434                };
435
436                ASSERTSOCKOP(send(fd, &socks5_hello, sizeof(socks5_hello), 0), "Sending auth request");
437
438                bt->phase = BS_PHASE_REQUEST;
439
440                bt->tf->watch_in = b_input_add(fd, B_EV_IO_READ, jabber_bs_recv_handshake, bt);
441
442                bt->tf->watch_out = 0;
443                return FALSE;
444        }
445        case BS_PHASE_REQUEST:
446        {
447                struct socks5_message socks5_connect =
448                {
449                        .ver = 5,
450                        .cmdrep.cmd = 0x01,
451                        .rsv = 0,
452                        .atyp = 0x03,
453                        .addrlen = strlen(bt->pseudoadr),
454                        .port = 0
455                };
456                int ret;
457                char buf[2];
458
459                /* If someone's trying to be funny and sends only one byte at a time we'll fail :) */
460                ASSERTSOCKOP(ret = recv(fd, buf, 2, 0), "Receiving auth reply");
461
462                if (!(ret == 2) ||
463                    !(buf[0] == 5) ||
464                    !(buf[1] == 0)) {
465                        return jabber_bs_abort(bt, "Auth not accepted by streamhost (reply: len=%d, ver=%d, status=%d)",
466                                               ret, buf[0], buf[1]);
467                }
468
469                /* copy hash into connect message */
470                memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen);
471
472                ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect");
473
474                bt->phase = BS_PHASE_REPLY;
475
476                return TRUE;
477        }
478        case BS_PHASE_REPLY:
479        {
480                struct socks5_message socks5_reply;
481                int ret;
482
483                if (!(ret = jabber_bs_peek(bt, &socks5_reply, sizeof(struct socks5_message)))) {
484                        return FALSE;
485                }
486
487                if (ret < 5) {         /* header up to address length */
488                        return TRUE;
489                } else if (ret < sizeof(struct socks5_message)) {
490                        /* Either a buggy proxy or just one that doesnt regard
491                         * the SHOULD in XEP-0065 saying the reply SHOULD
492                         * contain the address. We'll take it, so make sure the
493                         * next jabber_bs_peek starts with an empty buffer. */
494                        bt->peek_buf_len = 0;
495                }
496
497                if (!(socks5_reply.ver == 5) ||
498                    !(socks5_reply.cmdrep.rep == 0)) {
499                        char errstr[128] = "";
500                        if ((socks5_reply.ver == 5) && (socks5_reply.cmdrep.rep <
501                                                        (sizeof(socks5_reply_code) / sizeof(socks5_reply_code[0])))) {
502                                sprintf(errstr, "with \"%s\" ", socks5_reply_code[ socks5_reply.cmdrep.rep ]);
503                        }
504                        return jabber_bs_abort(bt,
505                                               "SOCKS5 CONNECT failed %s(reply: ver=%d, rep=%d, atyp=%d, addrlen=%d)",
506                                               errstr,
507                                               socks5_reply.ver,
508                                               socks5_reply.cmdrep.rep,
509                                               socks5_reply.atyp,
510                                               socks5_reply.addrlen);
511                }
512
513                /* usually a proxy sends back the 40 bytes address but I encountered at least one (of jabber.cz)
514                 * that sends atyp=0 addrlen=0 and only 6 bytes (one less than one would expect).
515                 * Therefore I removed the wait for more bytes. Since we don't care about what else the proxy
516                 * is sending, it shouldnt matter */
517
518                if (bt->tf->ft->sending) {
519                        jabber_bs_send_activate(bt);
520                } else {
521                        jabber_bs_recv_answer_request(bt);
522                }
523
524                return FALSE;
525        }
526        default:
527                /* BUG */
528                imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase");
529
530                bt->tf->watch_in = 0;
531                return FALSE;
532        }
533}
534
535/*
536 * If the handshake failed we can try the next streamhost, if there is one.
537 * An intelligent sender would probably specify himself as the first streamhost and
538 * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially)
539 * slow proxy is only used if neccessary. This of course also means, that the timeout
540 * per streamhost should be kept short. If one or two firewalled adresses are specified,
541 * they have to timeout first before a proxy is tried.
542 */
543gboolean jabber_bs_recv_handshake_abort(struct bs_transfer *bt, char *error)
544{
545        struct jabber_transfer *tf = bt->tf;
546        struct xt_node *reply, *iqnode;
547        GSList *shlist;
548
549        imcb_log(tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",
550                 tf->ft->file_name,
551                 bt->sh->host,
552                 bt->sh->port,
553                 error);
554
555        /* Alright, this streamhost failed, let's try the next... */
556        bt->phase = BS_PHASE_CONNECT;
557        shlist = g_slist_find(bt->streamhosts, bt->sh);
558        if (shlist && shlist->next) {
559                bt->sh = shlist->next->data;
560                return jabber_bs_recv_handshake(bt, -1, 0);
561        }
562
563
564        /* out of stream hosts */
565
566        iqnode = jabber_make_packet("iq", "result", tf->ini_jid, NULL);
567        reply = jabber_make_error_packet(iqnode, "item-not-found", "cancel", "404");
568        xt_free_node(iqnode);
569
570        xt_add_attr(reply, "id", tf->iq_id);
571
572        if (!jabber_write_packet(tf->ic, reply)) {
573                imcb_log(tf->ic, "WARNING: Error transmitting bytestream response");
574        }
575        xt_free_node(reply);
576
577        imcb_file_canceled(tf->ic, tf->ft, "couldn't connect to any streamhosts");
578
579        /* MUST always return FALSE! */
580        return FALSE;
581}
582
583/*
584 * After the SOCKS5 handshake succeeds we need to inform the initiator which streamhost we chose.
585 * If he is the streamhost himself, he might already know that. However, if it's a proxy,
586 * the initiator will have to make a connection himself.
587 */
588void jabber_bs_recv_answer_request(struct bs_transfer *bt)
589{
590        struct jabber_transfer *tf = bt->tf;
591        struct xt_node *reply;
592
593        imcb_log(tf->ic, "File %s: established SOCKS5 connection to %s:%s",
594                 tf->ft->file_name,
595                 bt->sh->host,
596                 bt->sh->port);
597
598        tf->ft->data = tf;
599        tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);
600        tf->ft->write_request = jabber_bs_recv_write_request;
601
602        reply = xt_new_node("streamhost-used", NULL, NULL);
603        xt_add_attr(reply, "jid", bt->sh->jid);
604
605        reply = xt_new_node("query", NULL, reply);
606        xt_add_attr(reply, "xmlns", XMLNS_BYTESTREAMS);
607
608        reply = jabber_make_packet("iq", "result", tf->ini_jid, reply);
609
610        xt_add_attr(reply, "id", tf->iq_id);
611
612        if (!jabber_write_packet(tf->ic, reply)) {
613                imcb_file_canceled(tf->ic, tf->ft, "Error transmitting bytestream response");
614        }
615        xt_free_node(reply);
616}
617
618/*
619 * This function is called from write_request directly. If no data is available, it will install itself
620 * as a watcher for input on fd and once that happens, deliver the data and unschedule itself again.
621 */
622gboolean jabber_bs_recv_read(gpointer data, gint fd, b_input_condition cond)
623{
624        int ret;
625        struct bs_transfer *bt = data;
626        struct jabber_transfer *tf = bt->tf;
627
628        if (fd != -1) { /* called via event thread */
629                tf->watch_in = 0;
630                ASSERTSOCKOP(ret = recv(fd, tf->ft->buffer, sizeof(tf->ft->buffer), 0), "Receiving");
631        } else {
632                /* called directly. There might not be any data available. */
633                if (((ret = recv(tf->fd, tf->ft->buffer, sizeof(tf->ft->buffer), 0)) == -1) &&
634                    (errno != EAGAIN)) {
635                        return jabber_bs_abort(bt, "Receiving: %s", strerror(errno));
636                }
637
638                if ((ret == -1) && (errno == EAGAIN)) {
639                        tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);
640                        return FALSE;
641                }
642        }
643
644        /* shouldn't happen since we know the file size */
645        if (ret == 0) {
646                return jabber_bs_abort(bt, "Remote end closed connection");
647        }
648
649        tf->bytesread += ret;
650
651        if (tf->bytesread >= tf->ft->file_size) {
652                imcb_file_finished(tf->ic, tf->ft);
653        }
654
655        tf->ft->write(tf->ft, tf->ft->buffer, ret);
656
657        return FALSE;
658}
659
660/*
661 * imc callback that is invoked when it is ready to receive some data.
662 */
663gboolean jabber_bs_recv_write_request(file_transfer_t *ft)
664{
665        struct jabber_transfer *tf = ft->data;
666
667        if (tf->watch_in) {
668                imcb_file_canceled(tf->ic, ft,
669                                   "BUG in jabber file transfer: write_request called when already watching for input");
670                return FALSE;
671        }
672
673        jabber_bs_recv_read(tf->streamhandle, -1, 0);
674
675        return TRUE;
676}
677
678/*
679 * Issues a write_request to imc.
680 * */
681gboolean jabber_bs_send_can_write(gpointer data, gint fd, b_input_condition cond)
682{
683        struct bs_transfer *bt = data;
684
685        bt->tf->watch_out = 0;
686
687        bt->tf->ft->write_request(bt->tf->ft);
688
689        return FALSE;
690}
691
692/*
693 * This should only be called if we can write, so just do it.
694 * Add a write watch so we can write more during the next cycle (if possible).
695 */
696gboolean jabber_bs_send_write(file_transfer_t *ft, char *buffer, unsigned int len)
697{
698        struct jabber_transfer *tf = ft->data;
699        struct bs_transfer *bt = tf->streamhandle;
700        int ret;
701
702        if (tf->watch_out) {
703                return jabber_bs_abort(bt, "BUG: write() called while watching ");
704        }
705
706        /* TODO: catch broken pipe */
707        ASSERTSOCKOP(ret = send(tf->fd, buffer, len, 0), "Sending");
708
709        tf->byteswritten += ret;
710
711        /* TODO: this should really not be fatal */
712        if (ret < len) {
713                return jabber_bs_abort(bt, "send() sent %d instead of %d (send buffer too big!)", ret, len);
714        }
715
716        if (tf->byteswritten >= ft->file_size) {
717                imcb_file_finished(tf->ic, ft);
718        } else {
719                bt->tf->watch_out = b_input_add(tf->fd, B_EV_IO_WRITE, jabber_bs_send_can_write, bt);
720        }
721
722        return TRUE;
723}
724
725/*
726 * Handles the reply by the receiver containing the used streamhost.
727 */
728static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
729{
730        struct jabber_transfer *tf = NULL;
731        struct jabber_data *jd = ic->proto_data;
732        struct bs_transfer *bt;
733        GSList *tflist;
734        struct xt_node *c;
735        char *sid, *jid;
736
737        if (!(c = xt_find_node(node->children, "query")) ||
738            !(c = xt_find_node(c->children, "streamhost-used")) ||
739            !(jid = xt_find_attr(c, "jid"))) {
740                imcb_log(ic, "WARNING: Received incomplete bytestream reply");
741                return XT_HANDLED;
742        }
743
744        if (!(c = xt_find_node(orig->children, "query")) ||
745            !(sid = xt_find_attr(c, "sid"))) {
746                imcb_log(ic, "WARNING: Error parsing request corresponding to the incoming bytestream reply");
747                return XT_HANDLED;
748        }
749
750        /* Let's see if we can find out what this bytestream should be for... */
751
752        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
753                struct jabber_transfer *tft = tflist->data;
754                if ((strcmp(tft->sid, sid) == 0)) {
755                        tf = tft;
756                        break;
757                }
758        }
759
760        if (!tf) {
761                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request");
762                return XT_HANDLED;
763        }
764
765        bt = tf->streamhandle;
766
767        tf->accepted = TRUE;
768
769        if (strcmp(jid, tf->ini_jid) == 0) {
770                /* we're streamhost and target */
771                if (bt->phase == BS_PHASE_REPLY) {
772                        /* handshake went through, let's start transferring */
773                        tf->ft->write_request(tf->ft);
774                }
775        } else {
776                /* using a proxy, abort listen */
777
778                if (tf->watch_in) {
779                        b_event_remove(tf->watch_in);
780                        tf->watch_in = 0;
781                }
782
783                if (tf->fd != -1) {
784                        closesocket(tf->fd);
785                        tf->fd = -1;
786                }
787
788                if (bt->connect_timeout) {
789                        b_event_remove(bt->connect_timeout);
790                        bt->connect_timeout = 0;
791                }
792
793                GSList *shlist;
794                for (shlist = jd->streamhosts; shlist; shlist = g_slist_next(shlist)) {
795                        jabber_streamhost_t *sh = shlist->data;
796                        if (strcmp(sh->jid, jid) == 0) {
797                                bt->sh = sh;
798                                jabber_bs_recv_handshake(bt, -1, 0);
799                                return XT_HANDLED;
800                        }
801                }
802
803                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid);
804        }
805
806        return XT_HANDLED;
807}
808
809/*
810 * Tell the proxy to activate the stream. Looks like this:
811 *
812 * <iq type=set>
813 *      <query xmlns=bs sid=sid>
814 *              <activate>tgt_jid</activate>
815 *      </query>
816 * </iq>
817 */
818void jabber_bs_send_activate(struct bs_transfer *bt)
819{
820        struct xt_node *node;
821
822        node = xt_new_node("activate", bt->tf->tgt_jid, NULL);
823        node = xt_new_node("query", NULL, node);
824        xt_add_attr(node, "xmlns", XMLNS_BYTESTREAMS);
825        xt_add_attr(node, "sid", bt->tf->sid);
826        node = jabber_make_packet("iq", "set", bt->sh->jid, node);
827
828        jabber_cache_add(bt->tf->ic, node, jabber_bs_send_handle_activate);
829
830        jabber_write_packet(bt->tf->ic, node);
831}
832
833/*
834 * The proxy has activated the bytestream.
835 * We can finally start pushing some data out.
836 */
837static xt_status jabber_bs_send_handle_activate(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
838{
839        char *sid;
840        GSList *tflist;
841        struct jabber_transfer *tf = NULL;
842        struct xt_node *query;
843        struct jabber_data *jd = ic->proto_data;
844
845        query = xt_find_node(orig->children, "query");
846        sid = xt_find_attr(query, "sid");
847
848        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
849                struct jabber_transfer *tft = tflist->data;
850                if ((strcmp(tft->sid, sid) == 0)) {
851                        tf = tft;
852                        break;
853                }
854        }
855
856        if (!tf) {
857                imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream");
858                return XT_HANDLED;
859        }
860
861        imcb_log(tf->ic, "File %s: SOCKS5 handshake and activation successful! Transfer about to start...",
862                 tf->ft->file_name);
863
864        /* handshake went through, let's start transferring */
865        tf->ft->write_request(tf->ft);
866
867        return XT_HANDLED;
868}
869
870jabber_streamhost_t *jabber_si_parse_proxy(struct im_connection *ic, char *proxy)
871{
872        char *host, *port, *jid;
873        jabber_streamhost_t *sh;
874
875        if (((host = strchr(proxy, ',')) == 0) ||
876            ((port = strchr(host + 1, ',')) == 0)) {
877                imcb_log(ic, "Error parsing proxy setting: \"%s\" (ignored)", proxy);
878                return NULL;
879        }
880
881        jid = proxy;
882        *host++ = '\0';
883        *port++ = '\0';
884
885        sh = g_new0(jabber_streamhost_t, 1);
886        sh->jid = g_strdup(jid);
887        sh->host = g_strdup(host);
888        g_snprintf(sh->port, sizeof(sh->port), "%s", port);
889
890        return sh;
891}
892
893void jabber_si_set_proxies(struct bs_transfer *bt)
894{
895        struct jabber_transfer *tf = bt->tf;
896        struct jabber_data *jd = tf->ic->proto_data;
897        char *proxysetting = g_strdup(set_getstr(&tf->ic->acc->set, "proxy"));
898        char *proxy, *next, *errmsg = NULL;
899        char port[6];
900        char host[HOST_NAME_MAX + 1];
901        jabber_streamhost_t *sh, *sh2;
902        GSList *streamhosts = jd->streamhosts;
903
904        proxy = proxysetting;
905        while (proxy && (*proxy != '\0')) {
906                if ((next = strchr(proxy, ';'))) {
907                        *next++ = '\0';
908                }
909
910                if (strcmp(proxy, "<local>") == 0) {
911                        if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) {
912                                sh = g_new0(jabber_streamhost_t, 1);
913                                sh->jid = g_strdup(tf->ini_jid);
914                                sh->host = g_strdup(host);
915                                g_snprintf(sh->port, sizeof(sh->port), "%s", port);
916                                bt->streamhosts = g_slist_append(bt->streamhosts, sh);
917
918                                bt->tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_send_handshake, bt);
919                                bt->connect_timeout = b_timeout_add(JABBER_BS_LISTEN_TIMEOUT * 1000,
920                                                                    jabber_bs_connect_timeout, bt);
921                        } else {
922                                imcb_log(tf->ic,
923                                         "Transferring file %s: couldn't listen locally(non fatal, check your ft_listen setting in bitlbee.conf): %s",
924                                         tf->ft->file_name,
925                                         errmsg);
926                        }
927                } else if (strcmp(proxy, "<auto>") == 0) {
928                        while (streamhosts) {
929                                sh = g_new0(jabber_streamhost_t, 1);
930                                sh2 = streamhosts->data;
931                                sh->jid = g_strdup(sh2->jid);
932                                sh->host = g_strdup(sh2->host);
933                                strcpy(sh->port, sh2->port);
934                                bt->streamhosts = g_slist_append(bt->streamhosts, sh);
935                                streamhosts = g_slist_next(streamhosts);
936                        }
937                } else if ((sh = jabber_si_parse_proxy(tf->ic, proxy))) {
938                        bt->streamhosts = g_slist_append(bt->streamhosts, sh);
939                }
940                proxy = next;
941        }
942}
943
944/*
945 * Starts a bytestream.
946 */
947gboolean jabber_bs_send_start(struct jabber_transfer *tf)
948{
949        struct bs_transfer *bt;
950        sha1_state_t sha;
951        char hash_hex[41];
952        unsigned char hash[20];
953        int i, ret;
954
955        /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
956        sha1_init(&sha);
957        sha1_append(&sha, (unsigned char *) tf->sid, strlen(tf->sid));
958        sha1_append(&sha, (unsigned char *) tf->ini_jid, strlen(tf->ini_jid));
959        sha1_append(&sha, (unsigned char *) tf->tgt_jid, strlen(tf->tgt_jid));
960        sha1_finish(&sha, hash);
961
962        for (i = 0; i < 20; i++) {
963                sprintf(hash_hex + i * 2, "%02x", hash[i]);
964        }
965
966        bt = g_new0(struct bs_transfer, 1);
967        bt->tf = tf;
968        bt->phase = BS_PHASE_CONNECT;
969        bt->pseudoadr = g_strdup(hash_hex);
970        tf->streamhandle = bt;
971        tf->ft->free = jabber_bs_free_transfer;
972        tf->ft->canceled = jabber_bs_canceled;
973
974        jabber_si_set_proxies(bt);
975
976        ret = jabber_bs_send_request(tf, bt->streamhosts);
977
978        return ret;
979}
980
981gboolean jabber_bs_send_request(struct jabber_transfer *tf, GSList *streamhosts)
982{
983        struct xt_node *shnode, *query, *iq;
984
985        query = xt_new_node("query", NULL, NULL);
986        xt_add_attr(query, "xmlns", XMLNS_BYTESTREAMS);
987        xt_add_attr(query, "sid", tf->sid);
988        xt_add_attr(query, "mode", "tcp");
989
990        while (streamhosts) {
991                jabber_streamhost_t *sh = streamhosts->data;
992                shnode = xt_new_node("streamhost", NULL, NULL);
993                xt_add_attr(shnode, "jid", sh->jid);
994                xt_add_attr(shnode, "host", sh->host);
995                xt_add_attr(shnode, "port", sh->port);
996
997                xt_add_child(query, shnode);
998
999                streamhosts = g_slist_next(streamhosts);
1000        }
1001
1002
1003        iq = jabber_make_packet("iq", "set", tf->tgt_jid, query);
1004        xt_add_attr(iq, "from", tf->ini_jid);
1005
1006        jabber_cache_add(tf->ic, iq, jabber_bs_send_handle_reply);
1007
1008        if (!jabber_write_packet(tf->ic, iq)) {
1009                imcb_file_canceled(tf->ic, tf->ft, "Error transmitting bytestream request");
1010        }
1011        return TRUE;
1012}
1013
1014gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error)
1015{
1016        struct jabber_transfer *tf = bt->tf;
1017        struct jabber_data *jd = tf->ic->proto_data;
1018
1019        /* TODO: did the receiver get here somehow??? */
1020        imcb_log(tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s",
1021                 tf->ft->file_name,
1022                 error);
1023
1024        if (jd->streamhosts == NULL) { /* we're done here unless we have a proxy to try */
1025                imcb_file_canceled(tf->ic, tf->ft, error);
1026        }
1027
1028        /* MUST always return FALSE! */
1029        return FALSE;
1030}
1031
1032/*
1033 * SOCKS5BYTESTREAM protocol for the sender
1034 */
1035gboolean jabber_bs_send_handshake(gpointer data, gint fd, b_input_condition cond)
1036{
1037        struct bs_transfer *bt = data;
1038        struct jabber_transfer *tf = bt->tf;
1039        short revents;
1040
1041        if (!jabber_bs_poll(bt, fd, &revents)) {
1042                return FALSE;
1043        }
1044
1045        switch (bt->phase) {
1046        case BS_PHASE_CONNECT:
1047        {
1048                struct sockaddr_storage clt_addr;
1049                socklen_t ssize = sizeof(clt_addr);
1050
1051                /* Connect */
1052
1053                ASSERTSOCKOP(tf->fd = accept(fd, (struct sockaddr *) &clt_addr, &ssize), "Accepting connection");
1054
1055                closesocket(fd);
1056                fd = tf->fd;
1057                sock_make_nonblocking(fd);
1058
1059                bt->phase = BS_PHASE_CONNECTED;
1060
1061                bt->tf->watch_in = b_input_add(fd, B_EV_IO_READ, jabber_bs_send_handshake, bt);
1062                return FALSE;
1063        }
1064        case BS_PHASE_CONNECTED:
1065        {
1066                int ret, have_noauth = FALSE;
1067                struct {
1068                        unsigned char ver;
1069                        unsigned char method;
1070                } socks5_auth_reply = { .ver = 5, .method = 0 };
1071                struct {
1072                        unsigned char ver;
1073                        unsigned char nmethods;
1074                        unsigned char method;
1075                } socks5_hello;
1076
1077                if (!(ret = jabber_bs_peek(bt, &socks5_hello, sizeof(socks5_hello)))) {
1078                        return FALSE;
1079                }
1080
1081                if (ret < sizeof(socks5_hello)) {
1082                        return TRUE;
1083                }
1084
1085                if (!(socks5_hello.ver == 5) ||
1086                    !(socks5_hello.nmethods >= 1) ||
1087                    !(socks5_hello.nmethods < 32)) {
1088                        return jabber_bs_abort(bt, "Invalid auth request ver=%d nmethods=%d method=%d",
1089                                               socks5_hello.ver, socks5_hello.nmethods, socks5_hello.method);
1090                }
1091
1092                have_noauth = socks5_hello.method == 0;
1093
1094                if (socks5_hello.nmethods > 1) {
1095                        char mbuf[32];
1096                        int i;
1097                        ASSERTSOCKOP(ret = recv(fd, mbuf, socks5_hello.nmethods - 1, 0), "Receiving auth methods");
1098                        if (ret < (socks5_hello.nmethods - 1)) {
1099                                return jabber_bs_abort(bt, "Partial auth request");
1100                        }
1101                        for (i = 0; !have_noauth && (i < socks5_hello.nmethods - 1); i++) {
1102                                if (mbuf[i] == 0) {
1103                                        have_noauth = TRUE;
1104                                }
1105                        }
1106                }
1107
1108                if (!have_noauth) {
1109                        return jabber_bs_abort(bt, "Auth request didn't include no authentication");
1110                }
1111
1112                ASSERTSOCKOP(send(fd, &socks5_auth_reply, sizeof(socks5_auth_reply), 0), "Sending auth reply");
1113
1114                bt->phase = BS_PHASE_REQUEST;
1115
1116                return TRUE;
1117        }
1118        case BS_PHASE_REQUEST:
1119        {
1120                struct socks5_message socks5_connect;
1121                int msgsize = sizeof(struct socks5_message);
1122                int ret;
1123
1124                if (!(ret = jabber_bs_peek(bt, &socks5_connect, msgsize))) {
1125                        return FALSE;
1126                }
1127
1128                if (ret < msgsize) {
1129                        return TRUE;
1130                }
1131
1132                if (!(socks5_connect.ver == 5) ||
1133                    !(socks5_connect.cmdrep.cmd == 1) ||
1134                    !(socks5_connect.atyp == 3) ||
1135                    !(socks5_connect.addrlen == 40)) {
1136                        return jabber_bs_abort(bt,
1137                                               "Invalid SOCKS5 Connect message (addrlen=%d, ver=%d, cmd=%d, atyp=%d)",
1138                                               socks5_connect.addrlen, socks5_connect.ver, socks5_connect.cmdrep.cmd,
1139                                               socks5_connect.atyp);
1140                }
1141                if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) {
1142                        return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest");
1143                }
1144
1145                socks5_connect.cmdrep.rep = 0;
1146
1147                ASSERTSOCKOP(send(fd, &socks5_connect, msgsize, 0), "Sending connect reply");
1148
1149                bt->phase = BS_PHASE_REPLY;
1150
1151                imcb_log(tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name);
1152
1153                if (tf->accepted) {
1154                        /* streamhost-used message came already in(possible?), let's start sending */
1155                        tf->ft->write_request(tf->ft);
1156                }
1157
1158                tf->watch_in = 0;
1159                return FALSE;
1160
1161        }
1162        default:
1163                /* BUG */
1164                imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase");
1165
1166                bt->tf->watch_in = 0;
1167                return FALSE;
1168        }
1169}
1170#undef ASSERTSOCKOP
Note: See TracBrowser for help on using the repository browser.