source: trunk/libtransmission/net.c @ 10508

Last change on this file since 10508 was 10508, checked in by charles, 12 years ago

(trunk libT) #3162 "allow optional end-user configuration of TCP_CONGESTION" -- add jch's implementation of this to trunk for 2.00

  • Property svn:keywords set to Date Rev Author Id
File size: 17.9 KB
Line 
1/******************************************************************************
2 *
3 * $Id: net.c 10508 2010-04-22 01:49:16Z charles $
4 *
5 * Copyright (c) 2005-2008 Transmission authors and contributors
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *****************************************************************************/
25
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <assert.h>
31
32#include <sys/types.h>
33
34#ifdef WIN32
35 #include <winsock2.h> /* inet_addr */
36 #include <WS2tcpip.h>
37#else
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <netinet/tcp.h>
41 #include <arpa/inet.h> /* inet_addr */
42 #include <netdb.h>
43 #include <fcntl.h>
44#endif
45#include <unistd.h>
46
47#include <stdarg.h> /* some 1.4.x versions of evutil.h need this */
48#include <evutil.h>
49
50#include "transmission.h"
51#include "fdlimit.h"
52#include "natpmp.h"
53#include "net.h"
54#include "peer-io.h"
55#include "platform.h"
56#include "session.h"
57#include "utils.h"
58
59#ifndef IN_MULTICAST
60#define IN_MULTICAST( a ) ( ( ( a ) & 0xf0000000 ) == 0xe0000000 )
61#endif
62
63const tr_address tr_in6addr_any = { TR_AF_INET6, { IN6ADDR_ANY_INIT } };
64const tr_address tr_inaddr_any = { TR_AF_INET, { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } };
65
66#ifdef WIN32
67static const char *
68inet_ntop( int af, const void *src, char *dst, socklen_t cnt )
69{
70    if (af == AF_INET)
71    {
72        struct sockaddr_in in;
73        memset( &in, 0, sizeof( in ) );
74        in.sin_family = AF_INET;
75        memcpy( &in.sin_addr, src, sizeof( struct in_addr ) );
76        getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in),
77                    dst, cnt, NULL, 0, NI_NUMERICHOST);
78        return dst;
79    }
80    else if (af == AF_INET6)
81    {
82        struct sockaddr_in6 in;
83        memset( &in, 0, sizeof( in ) );
84        in.sin6_family = AF_INET6;
85        memcpy( &in.sin6_addr, src, sizeof( struct in_addr6 ) );
86        getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6),
87                    dst, cnt, NULL, 0, NI_NUMERICHOST);
88        return dst;
89    }
90    return NULL;
91}
92
93static int
94inet_pton(int af, const char *src, void *dst)
95{
96    struct addrinfo hints;
97    struct addrinfo *res;
98    struct addrinfo *ressave;
99
100    memset(&hints, 0, sizeof(struct addrinfo));
101    hints.ai_family = af;
102
103    if (getaddrinfo(src, NULL, &hints, &res) != 0)
104        return -1;
105
106    ressave = res;
107
108    while (res)
109    {
110        memcpy(dst, res->ai_addr, res->ai_addrlen);
111        res = res->ai_next;
112    }
113
114    freeaddrinfo(ressave);
115    return 0;
116}
117
118#endif
119
120
121void
122tr_netInit( void )
123{
124    static int initialized = FALSE;
125
126    if( !initialized )
127    {
128#ifdef WIN32
129        WSADATA wsaData;
130        WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
131#endif
132        initialized = TRUE;
133    }
134}
135
136const char *
137tr_ntop( const tr_address * src, char * dst, int size )
138{
139    assert( tr_isAddress( src ) );
140
141    if( src->type == TR_AF_INET )
142        return inet_ntop( AF_INET, &src->addr, dst, size );
143    else
144        return inet_ntop( AF_INET6, &src->addr, dst, size );
145}
146
147/*
148 * Non-threadsafe version of tr_ntop, which uses a static memory area for a buffer.
149 * This function is suitable to be called from libTransmission's networking code,
150 * which is single-threaded.
151 */
152const char *
153tr_ntop_non_ts( const tr_address * src )
154{
155    static char buf[INET6_ADDRSTRLEN];
156    return tr_ntop( src, buf, sizeof( buf ) );
157}
158
159tr_address *
160tr_pton( const char * src, tr_address * dst )
161{
162    int retval = inet_pton( AF_INET, src, &dst->addr );
163    assert( dst );
164    if( retval < 0 )
165        return NULL;
166    else if( retval == 0 )
167        retval = inet_pton( AF_INET6, src, &dst->addr );
168    else
169    {
170        dst->type = TR_AF_INET;
171        return dst;
172    }
173
174    if( retval < 1 )
175        return NULL;
176    dst->type = TR_AF_INET6;
177    return dst;
178}
179
180/*
181 * Compare two tr_address structures.
182 * Returns:
183 * <0 if a < b
184 * >0 if a > b
185 * 0  if a == b
186 */
187int
188tr_compareAddresses( const tr_address * a, const tr_address * b)
189{
190    static const int sizes[2] = { sizeof(struct in_addr), sizeof(struct in6_addr) };
191
192    assert( tr_isAddress( a ) );
193    assert( tr_isAddress( b ) );
194
195    /* IPv6 addresses are always "greater than" IPv4 */
196    if( a->type != b->type )
197        return a->type == TR_AF_INET ? 1 : -1;
198
199    return memcmp( &a->addr, &b->addr, sizes[a->type] );
200}
201
202/***********************************************************************
203 * TCP sockets
204 **********************************************************************/
205
206int
207tr_netSetTOS( int s, int tos )
208{
209#ifdef IP_TOS
210    return setsockopt( s, IPPROTO_IP, IP_TOS, (char*)&tos, sizeof( tos ) );
211#else
212    return 0;
213#endif
214}
215
216int
217tr_netSetCongestionControl( int s, const char *algorithm )
218{
219#ifdef TCP_CONGESTION
220    return setsockopt( s, IPPROTO_TCP, TCP_CONGESTION,
221                       algorithm, strlen(algorithm) + 1 );
222#else
223    errno = ENOSYS;
224    return -1;
225#endif
226}
227
228static socklen_t
229setup_sockaddr( const tr_address        * addr,
230                tr_port                   port,
231                struct sockaddr_storage * sockaddr)
232{
233    assert( tr_isAddress( addr ) );
234
235    if( addr->type == TR_AF_INET )
236    {
237        struct sockaddr_in  sock4;
238        memset( &sock4, 0, sizeof( sock4 ) );
239        sock4.sin_family      = AF_INET;
240        sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
241        sock4.sin_port        = port;
242        memcpy( sockaddr, &sock4, sizeof( sock4 ) );
243        return sizeof( struct sockaddr_in );
244    }
245    else
246    {
247        struct sockaddr_in6 sock6;
248        memset( &sock6, 0, sizeof( sock6 ) );
249        sock6.sin6_family   = AF_INET6;
250        sock6.sin6_port     = port;
251        sock6.sin6_flowinfo = 0;
252        sock6.sin6_addr     = addr->addr.addr6;
253        memcpy( sockaddr, &sock6, sizeof( sock6 ) );
254        return sizeof( struct sockaddr_in6 );
255    }
256}
257
258int
259tr_netOpenPeerSocket( tr_session        * session,
260                      const tr_address  * addr,
261                      tr_port             port,
262                      tr_bool             clientIsSeed )
263{
264    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
265    int                     s;
266    struct sockaddr_storage sock;
267    socklen_t               addrlen;
268    const tr_address      * source_addr;
269    socklen_t               sourcelen;
270    struct sockaddr_storage source_sock;
271
272    assert( tr_isAddress( addr ) );
273
274    if( !tr_isValidPeerAddress( addr, port ) )
275        return -EINVAL;
276
277    s = tr_fdSocketCreate( session, domains[addr->type], SOCK_STREAM );
278    if( s < 0 )
279        return -1;
280
281    /* seeds don't need much of a read buffer... */
282    if( clientIsSeed ) {
283        int n = 8192;
284        if( setsockopt( s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n) ) )
285            tr_inf( "Unable to set SO_RCVBUF on socket %d: %s", s, tr_strerror( sockerrno ) );
286    }
287
288    if( evutil_make_socket_nonblocking( s ) < 0 ) {
289        tr_netClose( session, s );
290        return -1;
291    }
292
293    addrlen = setup_sockaddr( addr, port, &sock );
294
295    /* set source address */
296    source_addr = tr_sessionGetPublicAddress( session, addr->type );
297    assert( source_addr );
298    sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
299    if( bind( s, ( struct sockaddr * ) &source_sock, sourcelen ) )
300    {
301        tr_err( _( "Couldn't set source address %s on %d: %s" ),
302                tr_ntop_non_ts( source_addr ), s, tr_strerror( errno ) );
303        return -errno;
304    }
305
306    if( ( connect( s, (struct sockaddr *) &sock,
307                  addrlen ) < 0 )
308#ifdef WIN32
309      && ( sockerrno != WSAEWOULDBLOCK )
310#endif
311      && ( sockerrno != EINPROGRESS ) )
312    {
313        int tmperrno;
314        tmperrno = sockerrno;
315        if( ( tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH )
316                || addr->type == TR_AF_INET )
317            tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
318                    s, tr_ntop_non_ts( addr ), (int)port, tmperrno,
319                    tr_strerror( tmperrno ) );
320        tr_netClose( session, s );
321        s = -tmperrno;
322    }
323
324    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
325               s, tr_peerIoAddrStr( addr, port ) );
326
327    return s;
328}
329
330static int
331tr_netBindTCPImpl( const tr_address * addr, tr_port port, tr_bool suppressMsgs, int * errOut )
332{
333    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
334    struct sockaddr_storage sock;
335    int fd;
336    int addrlen;
337    int optval;
338
339    assert( tr_isAddress( addr ) );
340
341    fd = socket( domains[addr->type], SOCK_STREAM, 0 );
342    if( fd < 0 ) {
343        *errOut = sockerrno;
344        return -1;
345    }
346
347    if( evutil_make_socket_nonblocking( fd ) < 0 ) {
348        *errOut = sockerrno;
349        tr_netCloseSocket( fd );
350        return -1;
351    }
352
353    optval = 1;
354    setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
355    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
356
357#ifdef IPV6_V6ONLY
358    if( addr->type == TR_AF_INET6 )
359        if( setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof( optval ) ) == -1 )
360            if( sockerrno != ENOPROTOOPT ) { /* if the kernel doesn't support it, ignore it */
361                *errOut = sockerrno;
362                return -1;
363            }
364#endif
365
366    addrlen = setup_sockaddr( addr, htons( port ), &sock );
367    if( bind( fd, (struct sockaddr *) &sock, addrlen ) ) {
368        const int err = sockerrno;
369        if( !suppressMsgs )
370        {
371            const char * fmt;
372            const char * hint;
373
374            if( err == EADDRINUSE )
375                hint = _( "Is another copy of Transmission already running?" );
376            else
377                hint = NULL;
378
379            if( hint == NULL )
380                fmt = _( "Couldn't bind port %d on %s: %s" );
381            else
382                fmt = _( "Couldn't bind port %d on %s: %s (%s)" );
383
384            tr_err( fmt, port, tr_ntop_non_ts( addr ), tr_strerror( err ), hint );
385        }
386        tr_netCloseSocket( fd );
387        *errOut = err;
388        return -1;
389    }
390
391    if( !suppressMsgs )
392        tr_dbg( "Bound socket %d to port %d on %s", fd, port, tr_ntop_non_ts( addr ) );
393
394    if( listen( fd, 128 ) == -1 ) {
395        *errOut = sockerrno;
396        tr_netCloseSocket( fd );
397        return -1;
398    }
399
400    return fd;
401}
402
403int
404tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
405{
406    int unused;
407    return tr_netBindTCPImpl( addr, port, suppressMsgs, &unused );
408}
409
410tr_bool
411tr_net_hasIPv6( tr_port port )
412{
413    static tr_bool result = FALSE;
414    static tr_bool alreadyDone = FALSE;
415
416    if( !alreadyDone )
417    {
418        int err;
419        int fd = tr_netBindTCPImpl( &tr_in6addr_any, port, TRUE, &err );
420        if( fd >= 0 || err != EAFNOSUPPORT ) /* we support ipv6 */
421            result = TRUE;
422        if( fd >= 0 )
423            tr_netCloseSocket( fd );
424        alreadyDone = TRUE;
425    }
426
427    return result;
428}
429
430int
431tr_netAccept( tr_session  * session,
432              int           b,
433              tr_address  * addr,
434              tr_port     * port )
435{
436    int fd = tr_fdSocketAccept( session, b, addr, port );
437
438    if( fd>=0 && evutil_make_socket_nonblocking(fd)<0 ) {
439        tr_netClose( session, fd );
440        fd = -1;
441    }
442
443    return fd;
444}
445
446void
447tr_netCloseSocket( int fd )
448{
449    EVUTIL_CLOSESOCKET( fd );
450}
451
452void
453tr_netClose( tr_session * session, int s )
454{
455    tr_fdSocketClose( session, s );
456}
457
458/*
459   get_source_address() and global_unicast_address() were written by
460   Juliusz Chroboczek, and are covered under the same license as dht.c.
461   Please feel free to copy them into your software if it can help
462   unbreaking the double-stack Internet. */
463
464/* Get the source address used for a given destination address.  Since
465   there is no official interface to get this information, we create
466   a connected UDP socket (connected UDP... hmm...) and check its source
467   address. */
468static int
469get_source_address( const struct sockaddr  * dst,
470                    socklen_t                dst_len,
471                    struct sockaddr        * src,
472                    socklen_t              * src_len )
473{
474    int s, rc, save;
475
476    s = socket(dst->sa_family, SOCK_DGRAM, 0);
477    if(s < 0)
478        goto fail;
479
480    /* Since it's a UDP socket, this doesn't actually send any packets. */
481    rc = connect(s, dst, dst_len);
482    if(rc < 0)
483        goto fail;
484
485    rc = getsockname(s, src, src_len);
486    if(rc < 0)
487        goto fail;
488
489    EVUTIL_CLOSESOCKET( s );
490
491    return rc;
492
493 fail:
494    save = errno;
495    EVUTIL_CLOSESOCKET( s );
496    errno = save;
497    return -1;
498}
499
500/* We all hate NATs. */
501static int
502global_unicast_address(struct sockaddr *sa)
503{
504    if(sa->sa_family == AF_INET) {
505        const unsigned char *a =
506            (unsigned char*)&((struct sockaddr_in*)sa)->sin_addr;
507        if(a[0] == 0 || a[0] == 127 || a[0] >= 224 ||
508           a[0] == 10 || (a[0] == 172 && a[1] >= 16 && a[1] <= 31) ||
509           (a[0] == 192 && a[1] == 168))
510            return 0;
511        return 1;
512    } else if(sa->sa_family == AF_INET6) {
513        const unsigned char *a =
514            (unsigned char*)&((struct sockaddr_in6*)sa)->sin6_addr;
515        /* 2000::/3 */
516        return (a[0] & 0xE0) == 0x20;
517    } else {
518        errno = EAFNOSUPPORT;
519        return -1;
520    }
521}
522
523static int
524tr_globalAddress( int af, void *addr, int *addr_len )
525{
526    struct sockaddr_storage ss;
527    socklen_t sslen = sizeof(ss);
528    struct sockaddr_in sin;
529    struct sockaddr_in6 sin6;
530    struct sockaddr *sa;
531    socklen_t salen;
532    int rc;
533
534    switch(af) {
535    case AF_INET:
536        memset(&sin, 0, sizeof(sin));
537        sin.sin_family = AF_INET;
538        inet_pton(AF_INET, "91.121.74.28", &sin.sin_addr);
539        sin.sin_port = htons(6969);
540        sa = (struct sockaddr*)&sin;
541        salen = sizeof(sin);
542        break;
543    case AF_INET6:
544        memset(&sin6, 0, sizeof(sin6));
545        sin6.sin6_family = AF_INET6;
546        /* In order for address selection to work right, this should be
547           a native IPv6 address, not Teredo or 6to4. */
548        inet_pton(AF_INET6, "2001:1890:1112:1::20", &sin6.sin6_addr);
549        sin6.sin6_port = htons(6969);
550        sa = (struct sockaddr*)&sin6;
551        salen = sizeof(sin6);
552        break;
553    default:
554        return -1;
555    }
556
557    rc = get_source_address( sa, salen, (struct sockaddr*)&ss, &sslen );
558
559    if( rc < 0 )
560        return -1;
561
562    if( !global_unicast_address( (struct sockaddr*)&ss) )
563        return -1;
564
565    switch(af) {
566    case AF_INET:
567        if(*addr_len < 4)
568            return -1;
569        memcpy(addr, &((struct sockaddr_in*)&ss)->sin_addr, 4);
570        *addr_len = 4;
571        return 1;
572    case AF_INET6:
573        if(*addr_len < 16)
574            return -1;
575        memcpy(addr, &((struct sockaddr_in6*)&ss)->sin6_addr, 16);
576        *addr_len = 16;
577        return 1;
578    default:
579        return -1;
580    }
581}
582
583/* Return our global IPv6 address, with caching. */
584
585const unsigned char *
586tr_globalIPv6( void )
587{
588    static unsigned char ipv6[16];
589    static time_t last_time = 0;
590    static int have_ipv6 = 0;
591    const time_t now = tr_time( );
592
593    /* Re-check every half hour */
594    if( last_time < now - 1800 )
595    {
596        int addrlen = 16;
597        const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen );
598        have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 );
599        last_time = now;
600    }
601
602    return have_ipv6 ? ipv6 : NULL;
603}
604
605/***
606****
607****
608***/
609
610static tr_bool
611isIPv4MappedAddress( const tr_address * addr )
612{
613    return ( addr->type == TR_AF_INET6 ) && IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 );
614}
615
616static tr_bool
617isIPv6LinkLocalAddress( const tr_address * addr )
618{
619    return ( ( addr->type == TR_AF_INET6 )
620                  && IN6_IS_ADDR_LINKLOCAL( &addr->addr.addr6 ) );
621}
622
623/* isMartianAddr was written by Juliusz Chroboczek,
624   and is covered under the same license as third-party/dht/dht.c. */
625static tr_bool
626isMartianAddr( const struct tr_address * a )
627{
628    static const unsigned char zeroes[16] =
629        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
630
631    assert( tr_isAddress( a ) );
632
633    switch( a->type )
634    {
635        case TR_AF_INET: {
636            const unsigned char * address = (const unsigned char*)&a->addr.addr4;
637            return (address[0] == 0) ||
638                   (address[0] == 127) ||
639                   ((address[0] & 0xE0) == 0xE0);
640            break;
641        }
642
643        case TR_AF_INET6: {
644            const unsigned char * address = (const unsigned char*)&a->addr.addr6;
645            return (address[0] == 0xFF) ||
646                   (memcmp(address, zeroes, 15) == 0 &&
647                    (address[15] == 0 || address[15] == 1)) ||
648                   /* Addresses outside of 2000::/3 are currently reserved,
649                      but might be allocated at some future time.  Since
650                      there are a lot of buggy peers pushing around such
651                      addresses over PEX, we reject them until the end of
652                      the 13th Baktun. */
653                   (tr_time() < 1356130800 && (address[0] & 0xE0) != 0x20);
654            break;
655        }
656
657        default:
658            return TRUE;
659    }
660}
661
662tr_bool
663tr_isValidPeerAddress( const tr_address * addr, tr_port port )
664{
665    return ( port != 0 )
666        && ( tr_isAddress( addr ) )
667        && ( !isIPv6LinkLocalAddress( addr ) )
668        && ( !isIPv4MappedAddress( addr ) )
669        && ( !isMartianAddr( addr ) );
670}
Note: See TracBrowser for help on using the repository browser.