source: protocols/jabber/s5bytestream.c @ cce0450

Last change on this file since cce0450 was cce0450, checked in by ulim <a.sporto+bee@…>, at 2008-06-02T12:49:33Z

Added textual SOCKS5 error messages.

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