source: protocols/jabber/s5bytestream.c @ 3355a82

Last change on this file since 3355a82 was 3355a82, checked in by ulim <a.sporto+bee@…>, at 2008-06-02T13:26:38Z

added a #define for AI_NUMERICSERV in s5bytestream.c (missing in ulibc).

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