source: protocols/jabber/s5bytestream.c @ 5ebff60

Last change on this file since 5ebff60 was 5ebff60, checked in by dequis <dx@…>, at 2015-02-20T22:50:54Z

Reindent everything to K&R style with tabs

Used uncrustify, with the configuration file in ./doc/uncrustify.cfg

Commit author set to "Indent <please@…>" so that it's easier to
skip while doing git blame.

  • Property mode set to 100644
File size: 32.7 KB
RevLine 
[2ff2076]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 "sha1.h"
[a02f34f]26#include "lib/ftutil.h"
[2ff2076]27#include <poll.h>
28
29struct bs_transfer {
30
31        struct jabber_transfer *tf;
32
[dc0ba9c]33        jabber_streamhost_t *sh;
34        GSList *streamhosts;
[2ff2076]35
[5ebff60]36        enum {
37                BS_PHASE_CONNECT,
38                BS_PHASE_CONNECTED,
39                BS_PHASE_REQUEST,
[2ff2076]40                BS_PHASE_REPLY
41        } phase;
42
43        /* SHA1( SID + Initiator JID + Target JID) */
44        char *pseudoadr;
45
46        gint connect_timeout;
[5ebff60]47
[a81d679]48        char peek_buf[64];
49        int peek_buf_len;
[2ff2076]50};
51
[5ebff60]52struct socks5_message {
[2ff2076]53        unsigned char ver;
[5ebff60]54        union {
[2ff2076]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;
[5ebff60]63} __attribute__ ((packed));
[2ff2076]64
[cce0450]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",
[5ebff60]75        "unassigned"
76};
[cce0450]77
[2ff2076]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) \
[5ebff60]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);
[2ff2076]107
108/*
109 * Frees a bs_transfer struct and calls the SI free function
110 */
[5ebff60]111void jabber_bs_free_transfer(file_transfer_t *ft)
112{
[2ff2076]113        struct jabber_transfer *tf = ft->data;
114        struct bs_transfer *bt = tf->streamhandle;
[dc0ba9c]115        jabber_streamhost_t *sh;
[2ff2076]116
[5ebff60]117        if (bt->connect_timeout) {
118                b_event_remove(bt->connect_timeout);
[2625d6d]119                bt->connect_timeout = 0;
120        }
121
[5ebff60]122        if (tf->watch_in) {
123                b_event_remove(tf->watch_in);
[8256ad5]124                tf->watch_in = 0;
125        }
[5ebff60]126
127        if (tf->watch_out) {
128                b_event_remove(tf->watch_out);
[8256ad5]129                tf->watch_out = 0;
130        }
[dc0ba9c]131
[5ebff60]132        g_free(bt->pseudoadr);
133
134        while (bt->streamhosts) {
[dc0ba9c]135                sh = bt->streamhosts->data;
[5ebff60]136                bt->streamhosts = g_slist_remove(bt->streamhosts, sh);
137                g_free(sh->jid);
138                g_free(sh->host);
139                g_free(sh);
[dc0ba9c]140        }
[dce3903]141
[5ebff60]142        g_free(bt);
143
144        jabber_si_free_transfer(ft);
[2ff2076]145}
146
[dc0ba9c]147/*
148 * Checks if buflen data is available on the socket and
149 * writes it to buffer if that's the case.
150 */
[5ebff60]151gboolean jabber_bs_peek(struct bs_transfer *bt, void *buffer, int buflen)
[2ff2076]152{
153        int ret;
154        int fd = bt->tf->fd;
155
[5ebff60]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");
[a81d679]162
[5ebff60]163        if (ret == 0) {
164                return jabber_bs_abort(bt, "Remote end closed connection");
165        }
[2ff2076]166
[a81d679]167        bt->peek_buf_len += ret;
[5ebff60]168        memcpy(buffer, bt->peek_buf, bt->peek_buf_len);
169
170        if (bt->peek_buf_len == buflen) {
[a81d679]171                /* If we have everything the caller wanted, reset the peek buffer. */
172                bt->peek_buf_len = 0;
173                return buflen;
[5ebff60]174        } else {
[a81d679]175                return bt->peek_buf_len;
[5ebff60]176        }
[2ff2076]177}
178
179
[5ebff60]180/*
[2ff2076]181 * This function is scheduled in bs_handshake via b_timeout_add after a (non-blocking) connect().
182 */
[5ebff60]183gboolean jabber_bs_connect_timeout(gpointer data, gint fd, b_input_condition cond)
[2ff2076]184{
185        struct bs_transfer *bt = data;
186
187        bt->connect_timeout = 0;
188
[5ebff60]189        jabber_bs_abort(bt, "no connection after %d seconds",
190                        bt->tf->ft->sending ? JABBER_BS_LISTEN_TIMEOUT : JABBER_BS_CONTIMEOUT);
[2ff2076]191
192        return FALSE;
193}
194
[5ebff60]195/*
[dc0ba9c]196 * Polls the socket, checks for errors and removes a connect timer
197 * if there is one.
198 */
[5ebff60]199gboolean jabber_bs_poll(struct bs_transfer *bt, int fd, short *revents)
[2ff2076]200{
[5ebff60]201        struct pollfd pfd = { .fd = fd, .events = POLLHUP | POLLERR };
202
203        if (bt->connect_timeout) {
204                b_event_remove(bt->connect_timeout);
[2ff2076]205                bt->connect_timeout = 0;
206        }
207
[5ebff60]208        ASSERTSOCKOP(poll(&pfd, 1, 0), "poll()")
[2ff2076]209
[5ebff60]210        if (pfd.revents & POLLERR) {
[2ff2076]211                int sockerror;
[5ebff60]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                }
[2ff2076]218
[5ebff60]219                if (bt->phase == BS_PHASE_CONNECTED) {
220                        return jabber_bs_abort(bt, "connect failed: %s", strerror(sockerror));
221                }
[2ff2076]222
[5ebff60]223                return jabber_bs_abort(bt, "Socket error during SOCKS5 handshake(weird!): %s", strerror(sockerror));
224        }
[2ff2076]225
[5ebff60]226        if (pfd.revents & POLLHUP) {
227                return jabber_bs_abort(bt, "Remote end closed connection");
[2ff2076]228        }
229
230        *revents = pfd.revents;
[5ebff60]231
[2ff2076]232        return TRUE;
233}
234
[dc0ba9c]235/*
236 * Used for receive and send path.
237 */
[5ebff60]238gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...)
[2ff2076]239{
240        va_list params;
[5ebff60]241
242        va_start(params, format);
[2ff2076]243        char error[128];
244
[5ebff60]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        }
[2ff2076]254}
255
256/* Bad luck */
[5ebff60]257void jabber_bs_canceled(file_transfer_t *ft, char *reason)
[2ff2076]258{
259        struct jabber_transfer *tf = ft->data;
260
[5ebff60]261        imcb_log(tf->ic, "File transfer aborted: %s", reason);
[2ff2076]262}
263
264/*
265 * Parses an incoming bytestream request and calls jabber_bs_handshake on success.
266 */
[5ebff60]267int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode)
[2ff2076]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;
[5ebff60]274        GSList *shlist = NULL;
[dc0ba9c]275        struct xt_node *shnode;
[2ff2076]276
277        sha1_state_t sha;
278        char hash_hex[41];
279        unsigned char hash[20];
280        int i;
[5ebff60]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");
[2ff2076]287                return XT_HANDLED;
288        }
289
[5ebff60]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"));
[2ff2076]294                return XT_HANDLED;
295        }
296
[dc0ba9c]297        shnode = qnode->children;
[5ebff60]298        while ((shnode = xt_find_node(shnode, "streamhost"))) {
[78d254f1]299                char *jid, *host, *port_s;
[dc0ba9c]300                int port;
[5ebff60]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);
[dc0ba9c]306                        sh->jid = g_strdup(jid);
307                        sh->host = g_strdup(host);
[5ebff60]308                        sprintf(sh->port, "%u", port);
309                        shlist = g_slist_append(shlist, sh);
[dc0ba9c]310                }
311                shnode = shnode->next;
312        }
[5ebff60]313
314        if (!shlist) {
315                imcb_log(ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries");
[dc0ba9c]316                return XT_HANDLED;
317        }
318
[2ff2076]319        /* Let's see if we can find out what this bytestream should be for... */
320
[5ebff60]321        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
[2ff2076]322                struct jabber_transfer *tft = tflist->data;
[5ebff60]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;
[2ff2076]327                        break;
328                }
329        }
330
[5ebff60]331        if (!tf) {
332                imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
[2ff2076]333                return XT_HANDLED;
334        }
335
336        /* iq_id and canceled can be reused since SI is done */
[5ebff60]337        g_free(tf->iq_id);
338        tf->iq_id = g_strdup(iq_id);
[2ff2076]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 */
[5ebff60]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);
[2ff2076]354        bt->tf = tf;
[dc0ba9c]355        bt->streamhosts = shlist;
356        bt->sh = shlist->data;
[2ff2076]357        bt->phase = BS_PHASE_CONNECT;
[5ebff60]358        bt->pseudoadr = g_strdup(hash_hex);
[2ff2076]359        tf->streamhandle = bt;
360        tf->ft->free = jabber_bs_free_transfer;
361
[5ebff60]362        jabber_bs_recv_handshake(bt, -1, 0);
[2ff2076]363
364        return XT_HANDLED;
365}
[dc0ba9c]366
[2ff2076]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 */
[5ebff60]374gboolean jabber_bs_recv_handshake(gpointer data, gint fd, b_input_condition cond)
[2ff2076]375{
376
377        struct bs_transfer *bt = data;
378        short revents;
[6cac643]379        int gret;
[2ff2076]380
[5ebff60]381        if ((fd != -1) && !jabber_bs_poll(bt, fd, &revents)) {
[2ff2076]382                return FALSE;
[5ebff60]383        }
384
385        switch (bt->phase) {
[2ff2076]386        case BS_PHASE_CONNECT:
[5ebff60]387        {
388                struct addrinfo hints, *rp;
389
390                memset(&hints, 0, sizeof(struct addrinfo));
391                hints.ai_socktype = SOCK_STREAM;
[2ff2076]392
[5ebff60]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                }
[2ff2076]396
[5ebff60]397                ASSERTSOCKOP(bt->tf->fd = fd = socket(rp->ai_family, rp->ai_socktype, 0), "Opening socket");
[2ff2076]398
[5ebff60]399                sock_make_nonblocking(fd);
[2ff2076]400
[5ebff60]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);
[2ff2076]403
[5ebff60]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                }
[2ff2076]408
[5ebff60]409                freeaddrinfo(rp);
[2ff2076]410
[5ebff60]411                bt->phase = BS_PHASE_CONNECTED;
[2ff2076]412
[5ebff60]413                bt->tf->watch_out = b_input_add(fd, B_EV_IO_WRITE, jabber_bs_recv_handshake, bt);
[2ff2076]414
[5ebff60]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);
[2ff2076]417
[5ebff60]418                bt->tf->watch_in = 0;
419                return FALSE;
420        }
[2ff2076]421        case BS_PHASE_CONNECTED:
[5ebff60]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 =
[2ff2076]448                {
[5ebff60]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)))) {
[2ff2076]484                        return FALSE;
485                }
486
[5ebff60]487                if (ret < 5) {         /* header up to address length */
[2ff2076]488                        return TRUE;
[5ebff60]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;
[2ff2076]495                }
496
[5ebff60]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 ]);
[cce0450]503                        }
[5ebff60]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                }
[2ff2076]512
[5ebff60]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 */
[2ff2076]517
[5ebff60]518                if (bt->tf->ft->sending) {
519                        jabber_bs_send_activate(bt);
520                } else {
521                        jabber_bs_recv_answer_request(bt);
[2ff2076]522                }
[5ebff60]523
524                return FALSE;
525        }
[2ff2076]526        default:
527                /* BUG */
[5ebff60]528                imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase");
[2ff2076]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
[5ebff60]538 * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially)
[dce3903]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.
[2ff2076]542 */
[5ebff60]543gboolean jabber_bs_recv_handshake_abort(struct bs_transfer *bt, char *error)
[2ff2076]544{
545        struct jabber_transfer *tf = bt->tf;
546        struct xt_node *reply, *iqnode;
[dc0ba9c]547        GSList *shlist;
548
[5ebff60]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);
[2ff2076]554
[dc0ba9c]555        /* Alright, this streamhost failed, let's try the next... */
556        bt->phase = BS_PHASE_CONNECT;
[5ebff60]557        shlist = g_slist_find(bt->streamhosts, bt->sh);
558        if (shlist && shlist->next) {
[dc0ba9c]559                bt->sh = shlist->next->data;
[5ebff60]560                return jabber_bs_recv_handshake(bt, -1, 0);
[2ff2076]561        }
562
[dc0ba9c]563
[2ff2076]564        /* out of stream hosts */
565
[5ebff60]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);
[2ff2076]571
[5ebff60]572        if (!jabber_write_packet(tf->ic, reply)) {
573                imcb_log(tf->ic, "WARNING: Error transmitting bytestream response");
574        }
575        xt_free_node(reply);
[2ff2076]576
[5ebff60]577        imcb_file_canceled(tf->ic, tf->ft, "couldn't connect to any streamhosts");
[2ff2076]578
[a81d679]579        /* MUST always return FALSE! */
[2ff2076]580        return FALSE;
581}
582
[5ebff60]583/*
[2ff2076]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 */
[5ebff60]588void jabber_bs_recv_answer_request(struct bs_transfer *bt)
[2ff2076]589{
590        struct jabber_transfer *tf = bt->tf;
591        struct xt_node *reply;
592
[5ebff60]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);
[2ff2076]597
598        tf->ft->data = tf;
[5ebff60]599        tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);
[dce3903]600        tf->ft->write_request = jabber_bs_recv_write_request;
[2ff2076]601
[5ebff60]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);
[2ff2076]607
[5ebff60]608        reply = jabber_make_packet("iq", "result", tf->ini_jid, reply);
[2ff2076]609
[5ebff60]610        xt_add_attr(reply, "id", tf->iq_id);
[2ff2076]611
[5ebff60]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);
[2ff2076]616}
617
[5ebff60]618/*
[dce3903]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 */
[5ebff60]622gboolean jabber_bs_recv_read(gpointer data, gint fd, b_input_condition cond)
[2ff2076]623{
624        int ret;
[dce3903]625        struct bs_transfer *bt = data;
626        struct jabber_transfer *tf = bt->tf;
[2ff2076]627
[5ebff60]628        if (fd != -1) { /* called via event thread */
[dce3903]629                tf->watch_in = 0;
[5ebff60]630                ASSERTSOCKOP(ret = recv(fd, tf->ft->buffer, sizeof(tf->ft->buffer), 0), "Receiving");
631        } else {
[dce3903]632                /* called directly. There might not be any data available. */
[5ebff60]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                }
[dce3903]637
[5ebff60]638                if ((ret == -1) && (errno == EAGAIN)) {
639                        tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);
[2ff2076]640                        return FALSE;
641                }
642        }
643
[dce3903]644        /* shouldn't happen since we know the file size */
[5ebff60]645        if (ret == 0) {
646                return jabber_bs_abort(bt, "Remote end closed connection");
647        }
648
[2ff2076]649        tf->bytesread += ret;
650
[5ebff60]651        if (tf->bytesread >= tf->ft->file_size) {
652                imcb_file_finished(tf->ic, tf->ft);
653        }
[4ac647d]654
[5ebff60]655        tf->ft->write(tf->ft, tf->ft->buffer, ret);
[2ff2076]656
[dce3903]657        return FALSE;
[2ff2076]658}
659
[5ebff60]660/*
[dce3903]661 * imc callback that is invoked when it is ready to receive some data.
662 */
[5ebff60]663gboolean jabber_bs_recv_write_request(file_transfer_t *ft)
[2ff2076]664{
665        struct jabber_transfer *tf = ft->data;
666
[5ebff60]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");
[dce3903]670                return FALSE;
671        }
[5ebff60]672
673        jabber_bs_recv_read(tf->streamhandle, -1, 0);
[2ff2076]674
[dce3903]675        return TRUE;
[2ff2076]676}
677
[5ebff60]678/*
[dce3903]679 * Issues a write_request to imc.
680 * */
[5ebff60]681gboolean jabber_bs_send_can_write(gpointer data, gint fd, b_input_condition cond)
[2ff2076]682{
683        struct bs_transfer *bt = data;
684
685        bt->tf->watch_out = 0;
[dce3903]686
[5ebff60]687        bt->tf->ft->write_request(bt->tf->ft);
[dce3903]688
[2ff2076]689        return FALSE;
690}
691
[dce3903]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 */
[5ebff60]696gboolean jabber_bs_send_write(file_transfer_t *ft, char *buffer, unsigned int len)
[2ff2076]697{
698        struct jabber_transfer *tf = ft->data;
699        struct bs_transfer *bt = tf->streamhandle;
700        int ret;
701
[5ebff60]702        if (tf->watch_out) {
703                return jabber_bs_abort(bt, "BUG: write() called while watching ");
704        }
705
[dc0ba9c]706        /* TODO: catch broken pipe */
[5ebff60]707        ASSERTSOCKOP(ret = send(tf->fd, buffer, len, 0), "Sending");
[dce3903]708
709        tf->byteswritten += ret;
[5ebff60]710
[dce3903]711        /* TODO: this should really not be fatal */
[5ebff60]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
[2ff2076]722        return TRUE;
723}
724
[dce3903]725/*
726 * Handles the reply by the receiver containing the used streamhost.
727 */
[5ebff60]728static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
729{
[2ff2076]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
[5ebff60]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");
[2ff2076]741                return XT_HANDLED;
742        }
[5ebff60]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");
[2ff2076]747                return XT_HANDLED;
748        }
749
750        /* Let's see if we can find out what this bytestream should be for... */
751
[5ebff60]752        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
[2ff2076]753                struct jabber_transfer *tft = tflist->data;
[5ebff60]754                if ((strcmp(tft->sid, sid) == 0)) {
755                        tf = tft;
[2ff2076]756                        break;
757                }
758        }
759
[5ebff60]760        if (!tf) {
761                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request");
[2ff2076]762                return XT_HANDLED;
763        }
764
765        bt = tf->streamhandle;
766
767        tf->accepted = TRUE;
768
[5ebff60]769        if (strcmp(jid, tf->ini_jid) == 0) {
[dc0ba9c]770                /* we're streamhost and target */
[5ebff60]771                if (bt->phase == BS_PHASE_REPLY) {
[dc0ba9c]772                        /* handshake went through, let's start transferring */
[5ebff60]773                        tf->ft->write_request(tf->ft);
[dc0ba9c]774                }
[5ebff60]775        } else {
[2625d6d]776                /* using a proxy, abort listen */
777
[5ebff60]778                if (tf->watch_in) {
779                        b_event_remove(tf->watch_in);
[29c1456]780                        tf->watch_in = 0;
781                }
[5ebff60]782
783                if (tf->fd != -1) {
784                        closesocket(tf->fd);
[8a90001]785                        tf->fd = -1;
786                }
[2625d6d]787
[5ebff60]788                if (bt->connect_timeout) {
789                        b_event_remove(bt->connect_timeout);
[2625d6d]790                        bt->connect_timeout = 0;
791                }
792
[dc0ba9c]793                GSList *shlist;
[5ebff60]794                for (shlist = jd->streamhosts; shlist; shlist = g_slist_next(shlist)) {
[dc0ba9c]795                        jabber_streamhost_t *sh = shlist->data;
[5ebff60]796                        if (strcmp(sh->jid, jid) == 0) {
[dc0ba9c]797                                bt->sh = sh;
[5ebff60]798                                jabber_bs_recv_handshake(bt, -1, 0);
[dc0ba9c]799                                return XT_HANDLED;
800                        }
801                }
802
[5ebff60]803                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid);
[2ff2076]804        }
805
806        return XT_HANDLED;
807}
808
[5ebff60]809/*
[dc0ba9c]810 * Tell the proxy to activate the stream. Looks like this:
811 *
812 * <iq type=set>
[5ebff60]813 *      <query xmlns=bs sid=sid>
814 *              <activate>tgt_jid</activate>
815 *      </query>
[dc0ba9c]816 * </iq>
817 */
[5ebff60]818void jabber_bs_send_activate(struct bs_transfer *bt)
[dc0ba9c]819{
820        struct xt_node *node;
821
[5ebff60]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);
[dc0ba9c]827
[5ebff60]828        jabber_cache_add(bt->tf->ic, node, jabber_bs_send_handle_activate);
[dc0ba9c]829
[5ebff60]830        jabber_write_packet(bt->tf->ic, node);
[dc0ba9c]831}
832
833/*
834 * The proxy has activated the bytestream.
835 * We can finally start pushing some data out.
836 */
[5ebff60]837static xt_status jabber_bs_send_handle_activate(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
[dc0ba9c]838{
839        char *sid;
840        GSList *tflist;
[b8a491d]841        struct jabber_transfer *tf = NULL;
[dc0ba9c]842        struct xt_node *query;
843        struct jabber_data *jd = ic->proto_data;
844
[5ebff60]845        query = xt_find_node(orig->children, "query");
846        sid = xt_find_attr(query, "sid");
[dc0ba9c]847
[5ebff60]848        for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
[dc0ba9c]849                struct jabber_transfer *tft = tflist->data;
[5ebff60]850                if ((strcmp(tft->sid, sid) == 0)) {
851                        tf = tft;
[dc0ba9c]852                        break;
853                }
854        }
855
[5ebff60]856        if (!tf) {
857                imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream");
[dc0ba9c]858                return XT_HANDLED;
859        }
860
[5ebff60]861        imcb_log(tf->ic, "File %s: SOCKS5 handshake and activation successful! Transfer about to start...",
862                 tf->ft->file_name);
[29c1456]863
[dc0ba9c]864        /* handshake went through, let's start transferring */
[5ebff60]865        tf->ft->write_request(tf->ft);
[dc0ba9c]866
867        return XT_HANDLED;
868}
869
[5ebff60]870jabber_streamhost_t *jabber_si_parse_proxy(struct im_connection *ic, char *proxy)
[8a90001]871{
872        char *host, *port, *jid;
873        jabber_streamhost_t *sh;
874
[5ebff60]875        if (((host = strchr(proxy, ',')) == 0) ||
876            ((port = strchr(host + 1, ',')) == 0)) {
877                imcb_log(ic, "Error parsing proxy setting: \"%s\" (ignored)", proxy);
[8a90001]878                return NULL;
879        }
[5ebff60]880
[8a90001]881        jid = proxy;
882        *host++ = '\0';
883        *port++ = '\0';
884
[5ebff60]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);
[8a90001]889
890        return sh;
891}
892
[5ebff60]893void jabber_si_set_proxies(struct bs_transfer *bt)
[8a90001]894{
895        struct jabber_transfer *tf = bt->tf;
896        struct jabber_data *jd = tf->ic->proto_data;
[5ebff60]897        char *proxysetting = g_strdup(set_getstr(&tf->ic->acc->set, "proxy"));
[a02f34f]898        char *proxy, *next, *errmsg = NULL;
[8a90001]899        char port[6];
[5ebff60]900        char host[HOST_NAME_MAX + 1];
[8a90001]901        jabber_streamhost_t *sh, *sh2;
902        GSList *streamhosts = jd->streamhosts;
903
904        proxy = proxysetting;
[5ebff60]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);
[a02f34f]921                        } else {
[5ebff60]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);
[a02f34f]926                        }
[5ebff60]927                } else if (strcmp(proxy, "<auto>") == 0) {
928                        while (streamhosts) {
929                                sh = g_new0(jabber_streamhost_t, 1);
[8a90001]930                                sh2 = streamhosts->data;
[5ebff60]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);
[8a90001]936                        }
[5ebff60]937                } else if ((sh = jabber_si_parse_proxy(tf->ic, proxy))) {
938                        bt->streamhosts = g_slist_append(bt->streamhosts, sh);
939                }
[8a90001]940                proxy = next;
941        }
942}
943
[dc0ba9c]944/*
945 * Starts a bytestream.
946 */
[5ebff60]947gboolean jabber_bs_send_start(struct jabber_transfer *tf)
[2ff2076]948{
949        struct bs_transfer *bt;
950        sha1_state_t sha;
951        char hash_hex[41];
952        unsigned char hash[20];
[5ebff60]953        int i, ret;
[2ff2076]954
955        /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
[5ebff60]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);
[2ff2076]967        bt->tf = tf;
968        bt->phase = BS_PHASE_CONNECT;
[5ebff60]969        bt->pseudoadr = g_strdup(hash_hex);
[2ff2076]970        tf->streamhandle = bt;
971        tf->ft->free = jabber_bs_free_transfer;
972        tf->ft->canceled = jabber_bs_canceled;
973
[5ebff60]974        jabber_si_set_proxies(bt);
[dc0ba9c]975
[5ebff60]976        ret = jabber_bs_send_request(tf, bt->streamhosts);
[dc0ba9c]977
978        return ret;
[2ff2076]979}
980
[5ebff60]981gboolean jabber_bs_send_request(struct jabber_transfer *tf, GSList *streamhosts)
[2ff2076]982{
[dc0ba9c]983        struct xt_node *shnode, *query, *iq;
[2ff2076]984
[5ebff60]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");
[dc0ba9c]989
[5ebff60]990        while (streamhosts) {
[dc0ba9c]991                jabber_streamhost_t *sh = streamhosts->data;
[5ebff60]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);
[dc0ba9c]996
[5ebff60]997                xt_add_child(query, shnode);
[dc0ba9c]998
[5ebff60]999                streamhosts = g_slist_next(streamhosts);
[dc0ba9c]1000        }
1001
[2ff2076]1002
[5ebff60]1003        iq = jabber_make_packet("iq", "set", tf->tgt_jid, query);
1004        xt_add_attr(iq, "from", tf->ini_jid);
[2ff2076]1005
[5ebff60]1006        jabber_cache_add(tf->ic, iq, jabber_bs_send_handle_reply);
[2ff2076]1007
[5ebff60]1008        if (!jabber_write_packet(tf->ic, iq)) {
1009                imcb_file_canceled(tf->ic, tf->ft, "Error transmitting bytestream request");
1010        }
[2ff2076]1011        return TRUE;
1012}
1013
[5ebff60]1014gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error)
[2ff2076]1015{
1016        struct jabber_transfer *tf = bt->tf;
[2625d6d]1017        struct jabber_data *jd = tf->ic->proto_data;
[2ff2076]1018
[dc0ba9c]1019        /* TODO: did the receiver get here somehow??? */
[5ebff60]1020        imcb_log(tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s",
1021                 tf->ft->file_name,
1022                 error);
[2ff2076]1023
[5ebff60]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        }
[2ff2076]1027
[a81d679]1028        /* MUST always return FALSE! */
[2ff2076]1029        return FALSE;
1030}
1031
1032/*
1033 * SOCKS5BYTESTREAM protocol for the sender
1034 */
[5ebff60]1035gboolean jabber_bs_send_handshake(gpointer data, gint fd, b_input_condition cond)
[2ff2076]1036{
1037        struct bs_transfer *bt = data;
1038        struct jabber_transfer *tf = bt->tf;
1039        short revents;
1040
[5ebff60]1041        if (!jabber_bs_poll(bt, fd, &revents)) {
[2ff2076]1042                return FALSE;
[5ebff60]1043        }
1044
1045        switch (bt->phase) {
[2ff2076]1046        case BS_PHASE_CONNECT:
[5ebff60]1047        {
1048                struct sockaddr_storage clt_addr;
1049                socklen_t ssize = sizeof(clt_addr);
[2ff2076]1050
[5ebff60]1051                /* Connect */
[2ff2076]1052
[5ebff60]1053                ASSERTSOCKOP(tf->fd = accept(fd, (struct sockaddr *) &clt_addr, &ssize), "Accepting connection");
[2ff2076]1054
[5ebff60]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)))) {
[2ff2076]1078                        return FALSE;
1079                }
1080
[5ebff60]1081                if (ret < sizeof(socks5_hello)) {
1082                        return TRUE;
1083                }
[2ff2076]1084
[5ebff60]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                }
[2ff2076]1091
[5ebff60]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                        }
[2ff2076]1106                }
1107
[5ebff60]1108                if (!have_noauth) {
1109                        return jabber_bs_abort(bt, "Auth request didn't include no authentication");
1110                }
[2ff2076]1111
[5ebff60]1112                ASSERTSOCKOP(send(fd, &socks5_auth_reply, sizeof(socks5_auth_reply), 0), "Sending auth reply");
[4358b10]1113
[5ebff60]1114                bt->phase = BS_PHASE_REQUEST;
[2ff2076]1115
[5ebff60]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                }
[2ff2076]1131
[5ebff60]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                }
[2ff2076]1144
[5ebff60]1145                socks5_connect.cmdrep.rep = 0;
[2ff2076]1146
[5ebff60]1147                ASSERTSOCKOP(send(fd, &socks5_connect, msgsize, 0), "Sending connect reply");
[dce3903]1148
[5ebff60]1149                bt->phase = BS_PHASE_REPLY;
[2ff2076]1150
[5ebff60]1151                imcb_log(tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name);
[2ff2076]1152
[5ebff60]1153                if (tf->accepted) {
1154                        /* streamhost-used message came already in(possible?), let's start sending */
1155                        tf->ft->write_request(tf->ft);
[2ff2076]1156                }
[5ebff60]1157
1158                tf->watch_in = 0;
1159                return FALSE;
1160
1161        }
[2ff2076]1162        default:
1163                /* BUG */
[5ebff60]1164                imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase");
[2ff2076]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.