source: protocols/jabber/s5bytestream.c @ 4358b10

Last change on this file since 4358b10 was 4358b10, checked in by ulim <a.sporto+bee@…>, at 2008-05-04T13:32:15Z

ulibc support, fixes "Invalid SOCKS5 Connect message" problem

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