source: trunk/libtransmission/tr-lpd.c @ 12226

Last change on this file since 12226 was 12226, checked in by jordan, 11 years ago

(trunk libT) copyediting: '#include "crypto.h"' cleanup

  • Property svn:keywords set to Date Rev Author Id
File size: 20.6 KB
Line 
1/*
2Copyright (c) 2010 by Johannes Lieder
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21*/
22
23/* ansi */
24#include <errno.h>
25#include <stdio.h>
26#include <string.h> /* strlen(), strncpy(), strstr(), memset() */
27
28/* posix */
29#include <signal.h> /* sig_atomic_t */
30#include <sys/time.h>
31#include <unistd.h> /* close() */
32#include <ctype.h> /* toupper() */
33#ifdef WIN32
34  #include <w32api.h>
35  #define WINDOWS  WindowsXP  /* freeaddrinfo(),getaddrinfo(),getnameinfo() */
36  #include <inttypes.h>
37  #include <ws2tcpip.h>
38  typedef uint16_t in_port_t;                   /* all missing */
39#else
40  #include <sys/types.h>
41  #include <sys/socket.h> /* socket(), bind() */
42  #include <netinet/in.h> /* sockaddr_in */
43#endif
44
45/* third party */
46#include <event2/event.h>
47#include <event2/util.h>
48
49/* libT */
50#include "transmission.h"
51#include "net.h"
52#include "peer-mgr.h" /* tr_peerMgrAddPex() */
53#include "session.h"
54#include "torrent.h" /* tr_torrentFindFromHash() */
55#include "tr-lpd.h"
56#include "utils.h"
57#include "version.h"
58
59/**
60* @brief Local Peer Discovery
61* @file tr-lpd.c
62*
63* This module implements the Local Peer Discovery (LPD) protocol as supported by the
64* uTorrent client application. A typical LPD datagram is 119 bytes long.
65*
66* $Id: tr-lpd.c 12226 2011-03-25 01:21:31Z jordan $
67*/
68
69static void event_callback( int, short, void* );
70
71enum {
72   UPKEEP_INTERVAL_SECS = 5
73};
74static struct event * upkeep_timer = NULL;
75
76static int lpd_socket; /**<separate multicast receive socket */
77static int lpd_socket2; /**<and multicast send socket */
78static struct event * lpd_event = NULL;
79static tr_port lpd_port;
80
81static tr_torrent* lpd_torStaticType UNUSED; /* just a helper for static type analysis */
82static tr_session* session;
83
84enum { lpd_maxDatagramLength = 200 }; /**<the size an LPD datagram must not exceed */
85const char lpd_mcastGroup[] = "239.192.152.143"; /**<LPD multicast group */
86const int lpd_mcastPort = 6771; /**<LPD source and destination UPD port */
87static struct sockaddr_in lpd_mcastAddr; /**<initialized from the above constants in tr_lpdInit */
88
89/**
90* @brief Protocol-related information carried by a Local Peer Discovery packet */
91struct lpd_protocolVersion
92{
93    int major, minor;
94};
95
96enum lpd_enumTimeToLive {
97    lpd_ttlSameSubnet = 1,
98    lpd_ttlSameSite = 32,
99    lpd_ttlSameRegion = 64,
100    lpd_ttlSameContinent = 128,
101    lpd_ttlUnrestricted = 255
102};
103
104enum {
105    lpd_announceInterval = 4 * 60, /**<4 min announce interval per torrent */
106    lpd_announceScope = lpd_ttlSameSubnet /**<the maximum scope for LPD datagrams */
107};
108
109
110/**
111* @defgroup DoS Message Flood Protection
112* @{
113* We want to have a means to protect the libtransmission backend against message
114* flooding: the strategy is to cap event processing once more than ten messages
115* per second (that is, taking the average over one of our housekeeping intervals)
116* got into our processing handler.
117* If we'd really hit the limit and start discarding events, we either joined an
118* extremely crowded multicast group or a malevolent host is sending bogus data to
119* our socket. In this situation, we rather miss some announcements than blocking
120* the actual task.
121* @}
122*/
123
124/**
125* @ingroup DoS
126* @brief allow at most ten messages per second (interval average)
127* @note this constraint is only enforced once per housekeeping interval */
128enum { lpd_announceCapFactor = 10 };
129
130/**
131* @ingroup DoS
132* @brief number of unsolicited messages during the last HK interval
133* @remark counts downwards */
134static int lpd_unsolicitedMsgCounter;
135
136/**
137* @def CRLF
138* @brief a line-feed, as understood by the LPD protocol */
139#define CRLF "\r\n"
140
141
142/**
143* @defgroup HttpReqProc HTTP-style request handling
144* @{
145*/
146
147/**
148* @brief Checks for BT-SEARCH method and separates the parameter section
149* @param[in] s The request string
150* @param[out] ver If non-NULL, gets filled with protocol info from the request
151* @return Returns a relative pointer to the beginning of the parameter section;
152*         if result is NULL, s was invalid and no information will be returned
153* @remark Note that the returned pointer is only usable as long as the given
154*         pointer s is valid; that is, return storage is temporary.
155*
156* Determines whether the given string checks out to be a valid BT-SEARCH message.
157* If so, the return value points to the beginning of the parameter section (note:
158* in this case the function returns a character sequence beginning with CRLF).
159* If parameter is not NULL, the declared protocol version is returned as part of
160* the lpd_protocolVersion structure.
161*/
162static const char* lpd_extractHeader( const char* s, struct lpd_protocolVersion* const ver )
163{
164    int major = -1, minor = -1;
165    size_t len;
166
167    assert( s != NULL );
168    len = strlen( s );
169
170    /* something might be rotten with this chunk of data */
171    if( len == 0 || len > lpd_maxDatagramLength )
172        return NULL;
173
174    /* now we can attempt to look up the BT-SEARCH header */
175    if( sscanf( s, "BT-SEARCH * HTTP/%d.%d" CRLF, &major, &minor ) != 2 )
176        return NULL;
177
178    if( major < 0 || minor < 0 )
179        return NULL;
180
181    {
182        /* a pair of blank lines at the end of the string, no place else */
183        const char* const two_blank = CRLF CRLF CRLF;
184        const char* const end = strstr( s, two_blank );
185
186        if( end == NULL || strlen( end ) > strlen( two_blank ) )
187            return NULL;
188    }
189
190    if( ver != NULL )
191    {
192        ver->major = major;
193        ver->minor = minor;
194    }
195
196    /* separate the header, begins with CRLF */
197    return strstr( s, CRLF );
198}
199
200/**
201* @brief Return the value of a named parameter
202*
203* @param[in] str Input string of "\r\nName: Value" pairs without HTTP-style method part
204* @param[in] name Name of parameter to extract
205* @param[in] n Maximum available storage for value to return
206* @param[out] val Output parameter for the actual value
207* @return Returns 1 if value could be copied successfully
208*
209* Extracts the associated value of a named parameter from a HTTP-style header by
210* performing the following steps:
211*   - assemble search string "\r\nName: " and locate position
212*   - copy back value from end to next "\r\n"
213*/
214static int lpd_extractParam( const char* const str, const char* const name, int n, char* const val )
215{
216    /* configure maximum length of search string here */
217    enum { maxLength = 30 };
218    char sstr[maxLength] = { };
219    const char* pos;
220
221    assert( str != NULL && name != NULL );
222    assert( val != NULL );
223
224    if( strlen( name ) > maxLength - strlen( CRLF ": " ) )
225        return 0;
226
227    /* compose the string token to search for */
228    snprintf( sstr, maxLength, CRLF "%s: ", name );
229
230    pos = strstr( str, sstr );
231    if( pos == NULL )
232        return 0; /* search was not successful */
233
234    {
235        const char* const beg = pos + strlen( sstr );
236        const char* const new_line = strstr( beg, CRLF );
237
238        /* the value is delimited by the next CRLF */
239        int len = new_line - beg;
240
241        /* if value string hits the length limit n,
242         * leave space for a trailing '\0' character */
243        if( len < n-- )
244            n = len;
245
246        strncpy( val, beg, n );
247        val[n] = 0;
248    }
249
250    /* we successfully returned the value string */
251    return 1;
252}
253
254/**
255* @} */
256
257static void on_upkeep_timer( int, short, void * );
258
259/**
260* @brief Initializes Local Peer Discovery for this node
261*
262* For the most part, this means setting up an appropriately configured multicast socket
263* and event-based message handling.
264*
265* @remark Since the LPD service does not use another protocol family yet, this code is
266* IPv4 only for the time being.
267*/
268int tr_lpdInit( tr_session* ss, tr_address* tr_addr UNUSED )
269{
270    struct ip_mreq mcastReq;
271    const int opt_on = 1, opt_off = 0;
272
273    if( session ) /* already initialized */
274        return -1;
275
276    assert( lpd_announceInterval > 0 );
277    assert( lpd_announceScope > 0 );
278
279    lpd_port = tr_sessionGetPeerPort( ss );
280    if( lpd_port <= 0 )
281        return -1;
282
283    tr_ndbg( "LPD", "Initialising Local Peer Discovery" );
284
285    /* setup datagram socket (receive) */
286    {
287        lpd_socket = socket( PF_INET, SOCK_DGRAM, 0 );
288        if( lpd_socket < 0 )
289            goto fail;
290
291        if( evutil_make_socket_nonblocking( lpd_socket ) < 0 )
292            goto fail;
293
294        if( setsockopt( lpd_socket, SOL_SOCKET, SO_REUSEADDR,
295                &opt_on, sizeof opt_on ) < 0 )
296            goto fail;
297
298        memset( &lpd_mcastAddr, 0, sizeof lpd_mcastAddr );
299        lpd_mcastAddr.sin_family = AF_INET;
300        lpd_mcastAddr.sin_port = htons( lpd_mcastPort );
301        if( evutil_inet_pton( lpd_mcastAddr.sin_family, lpd_mcastGroup,
302                &lpd_mcastAddr.sin_addr ) < 0 )
303            goto fail;
304
305        if( bind( lpd_socket, (struct sockaddr*) &lpd_mcastAddr,
306                sizeof lpd_mcastAddr ) < 0 )
307            goto fail;
308
309        /* we want to join that LPD multicast group */
310        memset( &mcastReq, 0, sizeof mcastReq );
311        mcastReq.imr_multiaddr = lpd_mcastAddr.sin_addr;
312        mcastReq.imr_interface.s_addr = htonl( INADDR_ANY );
313        if( setsockopt( lpd_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
314                &mcastReq, sizeof mcastReq ) < 0 )
315            goto fail;
316
317        if( setsockopt( lpd_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
318                &opt_off, sizeof opt_off ) < 0 )
319            goto fail;
320    }
321
322    /* setup datagram socket (send) */
323    {
324        const unsigned char scope = lpd_announceScope;
325
326        lpd_socket2 = socket( PF_INET, SOCK_DGRAM, 0 );
327        if( lpd_socket2 < 0 )
328            goto fail;
329
330        if( evutil_make_socket_nonblocking( lpd_socket2 ) < 0 )
331            goto fail;
332
333        /* configure outbound multicast TTL */
334        if( setsockopt( lpd_socket2, IPPROTO_IP, IP_MULTICAST_TTL,
335                &scope, sizeof scope ) < 0 )
336            goto fail;
337
338        if( setsockopt( lpd_socket2, IPPROTO_IP, IP_MULTICAST_LOOP,
339                &opt_off, sizeof opt_off ) < 0 )
340            goto fail;
341    }
342
343    session = ss;
344
345    /* Note: lpd_unsolicitedMsgCounter remains 0 until the first timeout event, thus
346     * any announcement received during the initial interval will be discarded. */
347
348    lpd_event = event_new( ss->event_base, lpd_socket, EV_READ | EV_PERSIST, event_callback, NULL );
349    event_add( lpd_event, NULL );
350
351    upkeep_timer = evtimer_new( ss->event_base, on_upkeep_timer, ss );
352    tr_timerAdd( upkeep_timer, UPKEEP_INTERVAL_SECS, 0 );
353
354    tr_ndbg( "LPD", "Local Peer Discovery initialised" );
355
356    return 1;
357
358    fail:
359    {
360        const int save = errno;
361        close( lpd_socket );
362        close( lpd_socket2 );
363        lpd_socket = lpd_socket2 = -1;
364        session = NULL;
365        tr_ndbg( "LPD", "LPD initialisation failed (errno = %d)", save );
366        errno = save;
367    }
368
369
370    return -1;
371}
372
373void tr_lpdUninit( tr_session* ss )
374{
375    if( session != ss )
376        return;
377
378    tr_ndbg( "LPD", "Uninitialising Local Peer Discovery" );
379
380    event_free( lpd_event );
381    lpd_event = NULL;
382
383    evtimer_del( upkeep_timer );
384    upkeep_timer = NULL;
385
386    /* just shut down, we won't remember any former nodes */
387    evutil_closesocket( lpd_socket );
388    evutil_closesocket( lpd_socket2 );
389    tr_ndbg( "LPD", "Done uninitialising Local Peer Discovery" );
390
391    session = NULL;
392}
393
394bool
395tr_lpdEnabled( const tr_session* ss )
396{
397    return ss && ( ss == session );
398}
399
400
401/**
402* @cond
403* @brief Performs some (internal) software consistency checks at compile time.
404* @remark Declared inline for the compiler not to allege us of feeding unused
405* functions. In any other respect, lpd_consistencyCheck is an orphaned function.
406*/
407static inline void lpd_consistencyCheck( void )
408{
409    /* if the following check fails, the definition of a hash string has changed
410     * without our knowledge; revise string handling in functions tr_lpdSendAnnounce
411     * and tr_lpdConsiderAnnounce. However, the code is designed to function as long
412     * as interfaces to the rest of the lib remain compatible with char* strings. */
413    STATIC_ASSERT( sizeof(lpd_torStaticType->info.hashString[0]) == sizeof(char) );
414}
415/**
416* @endcond */
417
418
419/**
420* @defgroup LdsProto LPD announcement processing
421* @{
422*/
423
424/**
425* @brief Announce the given torrent on the local network
426*
427* @param[in] t Torrent to announce
428* @return Returns true on success
429*
430* Send a query for torrent t out to the LPD multicast group (or the LAN, for that
431* matter). A listening client on the same network might react by adding us to his
432* peer pool for torrent t.
433*/
434bool
435tr_lpdSendAnnounce( const tr_torrent* t )
436{
437    size_t i;
438    const char fmt[] =
439        "BT-SEARCH * HTTP/%u.%u" CRLF
440        "Host: %s:%u" CRLF
441        "Port: %u" CRLF
442        "Infohash: %s" CRLF
443        CRLF
444        CRLF;
445
446    char hashString[lengthof( t->info.hashString )];
447    char query[lpd_maxDatagramLength + 1] = { };
448
449    if( t == NULL )
450        return false;
451
452    /* make sure the hash string is normalized, just in case */
453    for( i = 0; i < sizeof hashString; i++ )
454        hashString[i] = toupper( t->info.hashString[i] );
455
456    /* prepare a zero-terminated announce message */
457    snprintf( query, lpd_maxDatagramLength + 1, fmt, 1, 1,
458        lpd_mcastGroup, lpd_mcastPort, lpd_port, hashString );
459
460    /* actually send the query out using [lpd_socket2] */
461    {
462        const int len = strlen( query );
463
464        /* destination address info has already been set up in tr_lpdInit(),
465         * so we refrain from preparing another sockaddr_in here */
466        int res = sendto( lpd_socket2, query, len, 0,
467            (const struct sockaddr*) &lpd_mcastAddr, sizeof lpd_mcastAddr );
468
469        if( res != len )
470            return false;
471    }
472
473    tr_tordbg( t, "LPD announce message away" );
474
475    return true;
476}
477
478/**
479* @brief Process incoming unsolicited messages and add the peer to the announced
480* torrent if all checks are passed.
481*
482* @param[in,out] peer Adress information of the peer to add
483* @param[in] msg The announcement message to consider
484* @return Returns 0 if any input parameter or the announce was invalid, 1 if the peer
485* was successfully added, -1 if not; a non-null return value indicates a side-effect to
486* the peer in/out parameter.
487*
488* @note The port information gets added to the peer structure if tr_lpdConsiderAnnounce
489* is able to extract the necessary information from the announce message. That is, if
490* return != 0, the caller may retrieve the value from the passed structure.
491*/
492static int tr_lpdConsiderAnnounce( tr_pex* peer, const char* const msg )
493{
494    enum
495    {
496        maxValueLen = 25,
497        maxHashLen = lengthof(lpd_torStaticType->info.hashString)
498    };
499
500    struct lpd_protocolVersion ver = { -1, -1 };
501    char value[maxValueLen] = { };
502    char hashString[maxHashLen] = { };
503    int res = 0, peerPort = 0;
504
505    if( peer != NULL && msg != NULL )
506    {
507        tr_torrent* tor = NULL;
508
509        const char* params = lpd_extractHeader( msg, &ver );
510        if( params == NULL || ver.major != 1 ) /* allow messages of protocol v1 */
511            return 0;
512
513        /* save the effort to check Host, which seems to be optional anyway */
514
515        if( lpd_extractParam( params, "Port", maxValueLen, value ) == 0 )
516            return 0;
517
518        /* determine announced peer port, refuse if value too large */
519        if( sscanf( value, "%d", &peerPort ) != 1 || peerPort > (in_port_t)-1 )
520            return 0;
521
522        peer->port = htons( peerPort );
523        res = -1; /* signal caller side-effect to peer->port via return != 0 */
524
525        if( lpd_extractParam( params, "Infohash", maxHashLen, hashString ) == 0 )
526            return res;
527
528        tor = tr_torrentFindFromHashString( session, hashString );
529
530        if( tr_isTorrent( tor ) && tr_torrentAllowsLPD( tor ) )
531        {
532            /* we found a suitable peer, add it to the torrent */
533            tr_peerMgrAddPex( tor, TR_PEER_FROM_LPD, peer, -1 );
534            tr_tordbg( tor, "Learned %d local peer from LPD (%s:%u)",
535                1, tr_ntop_non_ts( &peer->addr ), peerPort );
536
537            /* periodic reconnectPulse() deals with the rest... */
538
539            return 1;
540        }
541        else
542            tr_ndbg( "LPD", "Cannot serve torrent #%s", hashString );
543    }
544
545    return res;
546}
547
548/**
549* @} */
550
551/**
552* @note Since it possible for tr_lpdAnnounceMore to get called from outside the LPD module,
553* the function needs to be informed of the externally employed housekeeping interval.
554* Further, by setting interval to zero (or negative) the caller may actually disable LPD
555* announces on a per-interval basis.
556*
557* FIXME: since this function's been made private and is called by a periodic timer,
558* most of the previous paragraph isn't true anymore... we weren't using that functionality
559* before. are there cases where we should? if not, should we remove the bells & whistles?
560*/
561static int
562tr_lpdAnnounceMore( const time_t now, const int interval )
563{
564    tr_torrent* tor = NULL;
565    int announcesSent = 0;
566
567    if( !tr_isSession( session ) )
568        return -1;
569
570    while(( tor = tr_torrentNext( session, tor ) )
571          && tr_sessionAllowsLPD( session ) )
572    {
573        if( tr_isTorrent( tor ) )
574        {
575            int announcePrio = 0;
576
577            if( !tr_torrentAllowsLPD( tor ) )
578                continue;
579
580            /* issue #3208: prioritize downloads before seeds */
581            switch( tr_torrentGetActivity( tor ) )
582            {
583            case TR_STATUS_DOWNLOAD:
584                announcePrio = 1;
585                break;
586            case TR_STATUS_SEED:
587                announcePrio = 2;
588                break;
589            default: /* fall through */
590                break;
591            }
592
593            if( announcePrio > 0 && tor->lpdAnnounceAt <= now )
594            {
595                if( tr_lpdSendAnnounce( tor ) )
596                    announcesSent++;
597
598                tor->lpdAnnounceAt = now +
599                    lpd_announceInterval * announcePrio;
600
601                break; /* that's enough; for this interval */
602            }
603        }
604    }
605
606    /* perform housekeeping for the flood protection mechanism */
607    {
608        const int maxAnnounceCap = interval * lpd_announceCapFactor;
609
610        if( lpd_unsolicitedMsgCounter < 0 )
611            tr_ninf( "LPD", "Dropped %d announces in the last interval (max. %d "
612                     "allowed)", -lpd_unsolicitedMsgCounter, maxAnnounceCap );
613
614        lpd_unsolicitedMsgCounter = maxAnnounceCap;
615    }
616
617    return announcesSent;
618}
619
620static void
621on_upkeep_timer( int foo UNUSED, short bar UNUSED, void * vsession UNUSED )
622{
623    const time_t now = tr_time( );
624    tr_lpdAnnounceMore( now, UPKEEP_INTERVAL_SECS );
625    tr_timerAdd( upkeep_timer, UPKEEP_INTERVAL_SECS, 0 );
626}
627
628/**
629* @brief Processing of timeout notifications and incoming data on the socket
630* @note maximum rate of read events is limited according to @a lpd_maxAnnounceCap
631* @see DoS */
632static void event_callback( int s UNUSED, short type, void* ignore UNUSED )
633{
634    assert( tr_isSession( session ) );
635
636    /* do not allow announces to be processed if LPD is disabled */
637    if( !tr_sessionAllowsLPD( session ) )
638        return;
639
640    if( ( type & EV_READ ) != 0 )
641    {
642        struct sockaddr_in foreignAddr;
643        int addrLen = sizeof foreignAddr;
644
645        /* be paranoid enough about zero terminating the foreign string */
646        char foreignMsg[lpd_maxDatagramLength + 1] = { };
647
648        /* process local announcement from foreign peer */
649        int res = recvfrom( lpd_socket, foreignMsg, lpd_maxDatagramLength,
650            0, (struct sockaddr*) &foreignAddr, (socklen_t*) &addrLen );
651
652        /* besides, do we get flooded? then bail out! */
653        if( --lpd_unsolicitedMsgCounter < 0 )
654            return;
655
656        if( res > 0 && res <= lpd_maxDatagramLength )
657        {
658            struct tr_pex foreignPeer =
659                {
660                    .port = 0, /* the peer-to-peer port is yet unknown */
661                    .flags = 0
662                };
663
664            foreignPeer.addr.addr.addr4 = foreignAddr.sin_addr;
665            if( tr_lpdConsiderAnnounce( &foreignPeer, foreignMsg ) != 0 )
666                return; /* OK so far, no log message */
667        }
668
669        tr_ndbg( "LPD", "Discarded invalid multicast message" );
670    }
671}
672
Note: See TracBrowser for help on using the repository browser.