source: trunk/libtransmission/net.c @ 10753

Last change on this file since 10753 was 10753, checked in by charles, 11 years ago

(trunk libT) remove a pair of unnecessary, but expensive, assert()s

  • Property svn:keywords set to Date Rev Author Id
File size: 17.9 KB
Line 
1/******************************************************************************
2 *
3 * $Id: net.c 10753 2010-06-14 23:14:58Z 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    /* IPv6 addresses are always "greater than" IPv4 */
193    if( a->type != b->type )
194        return a->type == TR_AF_INET ? 1 : -1;
195
196    return memcmp( &a->addr, &b->addr, sizes[a->type] );
197}
198
199/***********************************************************************
200 * TCP sockets
201 **********************************************************************/
202
203int
204tr_netSetTOS( int s, int tos )
205{
206#ifdef IP_TOS
207    return setsockopt( s, IPPROTO_IP, IP_TOS, (char*)&tos, sizeof( tos ) );
208#else
209    return 0;
210#endif
211}
212
213int
214tr_netSetCongestionControl( int s, const char *algorithm )
215{
216#ifdef TCP_CONGESTION
217    return setsockopt( s, IPPROTO_TCP, TCP_CONGESTION,
218                       algorithm, strlen(algorithm) + 1 );
219#else
220    errno = ENOSYS;
221    return -1;
222#endif
223}
224
225static socklen_t
226setup_sockaddr( const tr_address        * addr,
227                tr_port                   port,
228                struct sockaddr_storage * sockaddr)
229{
230    assert( tr_isAddress( addr ) );
231
232    if( addr->type == TR_AF_INET )
233    {
234        struct sockaddr_in  sock4;
235        memset( &sock4, 0, sizeof( sock4 ) );
236        sock4.sin_family      = AF_INET;
237        sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
238        sock4.sin_port        = port;
239        memcpy( sockaddr, &sock4, sizeof( sock4 ) );
240        return sizeof( struct sockaddr_in );
241    }
242    else
243    {
244        struct sockaddr_in6 sock6;
245        memset( &sock6, 0, sizeof( sock6 ) );
246        sock6.sin6_family   = AF_INET6;
247        sock6.sin6_port     = port;
248        sock6.sin6_flowinfo = 0;
249        sock6.sin6_addr     = addr->addr.addr6;
250        memcpy( sockaddr, &sock6, sizeof( sock6 ) );
251        return sizeof( struct sockaddr_in6 );
252    }
253}
254
255int
256tr_netOpenPeerSocket( tr_session        * session,
257                      const tr_address  * addr,
258                      tr_port             port,
259                      tr_bool             clientIsSeed )
260{
261    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
262    int                     s;
263    struct sockaddr_storage sock;
264    socklen_t               addrlen;
265    const tr_address      * source_addr;
266    socklen_t               sourcelen;
267    struct sockaddr_storage source_sock;
268
269    assert( tr_isAddress( addr ) );
270
271    if( !tr_isValidPeerAddress( addr, port ) )
272        return -EINVAL;
273
274    s = tr_fdSocketCreate( session, domains[addr->type], SOCK_STREAM );
275    if( s < 0 )
276        return -1;
277
278    /* seeds don't need much of a read buffer... */
279    if( clientIsSeed ) {
280        int n = 8192;
281        if( setsockopt( s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n) ) )
282            tr_inf( "Unable to set SO_RCVBUF on socket %d: %s", s, tr_strerror( sockerrno ) );
283    }
284
285    if( evutil_make_socket_nonblocking( s ) < 0 ) {
286        tr_netClose( session, s );
287        return -1;
288    }
289
290    addrlen = setup_sockaddr( addr, port, &sock );
291
292    /* set source address */
293    source_addr = tr_sessionGetPublicAddress( session, addr->type );
294    assert( source_addr );
295    sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
296    if( bind( s, ( struct sockaddr * ) &source_sock, sourcelen ) )
297    {
298        tr_err( _( "Couldn't set source address %s on %d: %s" ),
299                tr_ntop_non_ts( source_addr ), s, tr_strerror( errno ) );
300        return -errno;
301    }
302
303    if( ( connect( s, (struct sockaddr *) &sock,
304                  addrlen ) < 0 )
305#ifdef WIN32
306      && ( sockerrno != WSAEWOULDBLOCK )
307#endif
308      && ( sockerrno != EINPROGRESS ) )
309    {
310        int tmperrno;
311        tmperrno = sockerrno;
312        if( ( tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH )
313                || addr->type == TR_AF_INET )
314            tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
315                    s, tr_ntop_non_ts( addr ), (int)port, tmperrno,
316                    tr_strerror( tmperrno ) );
317        tr_netClose( session, s );
318        s = -tmperrno;
319    }
320
321    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
322               s, tr_peerIoAddrStr( addr, port ) );
323
324    return s;
325}
326
327static int
328tr_netBindTCPImpl( const tr_address * addr, tr_port port, tr_bool suppressMsgs, int * errOut )
329{
330    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
331    struct sockaddr_storage sock;
332    int fd;
333    int addrlen;
334    int optval;
335
336    assert( tr_isAddress( addr ) );
337
338    fd = socket( domains[addr->type], SOCK_STREAM, 0 );
339    if( fd < 0 ) {
340        *errOut = sockerrno;
341        return -1;
342    }
343
344    if( evutil_make_socket_nonblocking( fd ) < 0 ) {
345        *errOut = sockerrno;
346        tr_netCloseSocket( fd );
347        return -1;
348    }
349
350    optval = 1;
351    setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
352    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
353
354#ifdef IPV6_V6ONLY
355    if( addr->type == TR_AF_INET6 )
356        if( setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof( optval ) ) == -1 )
357            if( sockerrno != ENOPROTOOPT ) { /* if the kernel doesn't support it, ignore it */
358                *errOut = sockerrno;
359                return -1;
360            }
361#endif
362
363    addrlen = setup_sockaddr( addr, htons( port ), &sock );
364    if( bind( fd, (struct sockaddr *) &sock, addrlen ) ) {
365        const int err = sockerrno;
366        if( !suppressMsgs )
367        {
368            const char * fmt;
369            const char * hint;
370
371            if( err == EADDRINUSE )
372                hint = _( "Is another copy of Transmission already running?" );
373            else
374                hint = NULL;
375
376            if( hint == NULL )
377                fmt = _( "Couldn't bind port %d on %s: %s" );
378            else
379                fmt = _( "Couldn't bind port %d on %s: %s (%s)" );
380
381            tr_err( fmt, port, tr_ntop_non_ts( addr ), tr_strerror( err ), hint );
382        }
383        tr_netCloseSocket( fd );
384        *errOut = err;
385        return -1;
386    }
387
388    if( !suppressMsgs )
389        tr_dbg( "Bound socket %d to port %d on %s", fd, port, tr_ntop_non_ts( addr ) );
390
391    if( listen( fd, 128 ) == -1 ) {
392        *errOut = sockerrno;
393        tr_netCloseSocket( fd );
394        return -1;
395    }
396
397    return fd;
398}
399
400int
401tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
402{
403    int unused;
404    return tr_netBindTCPImpl( addr, port, suppressMsgs, &unused );
405}
406
407tr_bool
408tr_net_hasIPv6( tr_port port )
409{
410    static tr_bool result = FALSE;
411    static tr_bool alreadyDone = FALSE;
412
413    if( !alreadyDone )
414    {
415        int err;
416        int fd = tr_netBindTCPImpl( &tr_in6addr_any, port, TRUE, &err );
417        if( fd >= 0 || err != EAFNOSUPPORT ) /* we support ipv6 */
418            result = TRUE;
419        if( fd >= 0 )
420            tr_netCloseSocket( fd );
421        alreadyDone = TRUE;
422    }
423
424    return result;
425}
426
427int
428tr_netAccept( tr_session  * session,
429              int           b,
430              tr_address  * addr,
431              tr_port     * port )
432{
433    int fd = tr_fdSocketAccept( session, b, addr, port );
434
435    if( fd>=0 && evutil_make_socket_nonblocking(fd)<0 ) {
436        tr_netClose( session, fd );
437        fd = -1;
438    }
439
440    return fd;
441}
442
443void
444tr_netCloseSocket( int fd )
445{
446    EVUTIL_CLOSESOCKET( fd );
447}
448
449void
450tr_netClose( tr_session * session, int s )
451{
452    tr_fdSocketClose( session, s );
453}
454
455/*
456   get_source_address() and global_unicast_address() were written by
457   Juliusz Chroboczek, and are covered under the same license as dht.c.
458   Please feel free to copy them into your software if it can help
459   unbreaking the double-stack Internet. */
460
461/* Get the source address used for a given destination address.  Since
462   there is no official interface to get this information, we create
463   a connected UDP socket (connected UDP... hmm...) and check its source
464   address. */
465static int
466get_source_address( const struct sockaddr  * dst,
467                    socklen_t                dst_len,
468                    struct sockaddr        * src,
469                    socklen_t              * src_len )
470{
471    int s, rc, save;
472
473    s = socket(dst->sa_family, SOCK_DGRAM, 0);
474    if(s < 0)
475        goto fail;
476
477    /* Since it's a UDP socket, this doesn't actually send any packets. */
478    rc = connect(s, dst, dst_len);
479    if(rc < 0)
480        goto fail;
481
482    rc = getsockname(s, src, src_len);
483    if(rc < 0)
484        goto fail;
485
486    EVUTIL_CLOSESOCKET( s );
487
488    return rc;
489
490 fail:
491    save = errno;
492    EVUTIL_CLOSESOCKET( s );
493    errno = save;
494    return -1;
495}
496
497/* We all hate NATs. */
498static int
499global_unicast_address(struct sockaddr *sa)
500{
501    if(sa->sa_family == AF_INET) {
502        const unsigned char *a =
503            (unsigned char*)&((struct sockaddr_in*)sa)->sin_addr;
504        if(a[0] == 0 || a[0] == 127 || a[0] >= 224 ||
505           a[0] == 10 || (a[0] == 172 && a[1] >= 16 && a[1] <= 31) ||
506           (a[0] == 192 && a[1] == 168))
507            return 0;
508        return 1;
509    } else if(sa->sa_family == AF_INET6) {
510        const unsigned char *a =
511            (unsigned char*)&((struct sockaddr_in6*)sa)->sin6_addr;
512        /* 2000::/3 */
513        return (a[0] & 0xE0) == 0x20;
514    } else {
515        errno = EAFNOSUPPORT;
516        return -1;
517    }
518}
519
520static int
521tr_globalAddress( int af, void *addr, int *addr_len )
522{
523    struct sockaddr_storage ss;
524    socklen_t sslen = sizeof(ss);
525    struct sockaddr_in sin;
526    struct sockaddr_in6 sin6;
527    struct sockaddr *sa;
528    socklen_t salen;
529    int rc;
530
531    switch(af) {
532    case AF_INET:
533        memset(&sin, 0, sizeof(sin));
534        sin.sin_family = AF_INET;
535        inet_pton(AF_INET, "91.121.74.28", &sin.sin_addr);
536        sin.sin_port = htons(6969);
537        sa = (struct sockaddr*)&sin;
538        salen = sizeof(sin);
539        break;
540    case AF_INET6:
541        memset(&sin6, 0, sizeof(sin6));
542        sin6.sin6_family = AF_INET6;
543        /* In order for address selection to work right, this should be
544           a native IPv6 address, not Teredo or 6to4. */
545        inet_pton(AF_INET6, "2001:1890:1112:1::20", &sin6.sin6_addr);
546        sin6.sin6_port = htons(6969);
547        sa = (struct sockaddr*)&sin6;
548        salen = sizeof(sin6);
549        break;
550    default:
551        return -1;
552    }
553
554    rc = get_source_address( sa, salen, (struct sockaddr*)&ss, &sslen );
555
556    if( rc < 0 )
557        return -1;
558
559    if( !global_unicast_address( (struct sockaddr*)&ss) )
560        return -1;
561
562    switch(af) {
563    case AF_INET:
564        if(*addr_len < 4)
565            return -1;
566        memcpy(addr, &((struct sockaddr_in*)&ss)->sin_addr, 4);
567        *addr_len = 4;
568        return 1;
569    case AF_INET6:
570        if(*addr_len < 16)
571            return -1;
572        memcpy(addr, &((struct sockaddr_in6*)&ss)->sin6_addr, 16);
573        *addr_len = 16;
574        return 1;
575    default:
576        return -1;
577    }
578}
579
580/* Return our global IPv6 address, with caching. */
581
582const unsigned char *
583tr_globalIPv6( void )
584{
585    static unsigned char ipv6[16];
586    static time_t last_time = 0;
587    static int have_ipv6 = 0;
588    const time_t now = tr_time( );
589
590    /* Re-check every half hour */
591    if( last_time < now - 1800 )
592    {
593        int addrlen = 16;
594        const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen );
595        have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 );
596        last_time = now;
597    }
598
599    return have_ipv6 ? ipv6 : NULL;
600}
601
602/***
603****
604****
605***/
606
607static tr_bool
608isIPv4MappedAddress( const tr_address * addr )
609{
610    return ( addr->type == TR_AF_INET6 ) && IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 );
611}
612
613static tr_bool
614isIPv6LinkLocalAddress( const tr_address * addr )
615{
616    return ( ( addr->type == TR_AF_INET6 )
617                  && IN6_IS_ADDR_LINKLOCAL( &addr->addr.addr6 ) );
618}
619
620/* isMartianAddr was written by Juliusz Chroboczek,
621   and is covered under the same license as third-party/dht/dht.c. */
622static tr_bool
623isMartianAddr( const struct tr_address * a )
624{
625    static const unsigned char zeroes[16] =
626        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
627
628    assert( tr_isAddress( a ) );
629
630    switch( a->type )
631    {
632        case TR_AF_INET: {
633            const unsigned char * address = (const unsigned char*)&a->addr.addr4;
634            return (address[0] == 0) ||
635                   (address[0] == 127) ||
636                   ((address[0] & 0xE0) == 0xE0);
637            break;
638        }
639
640        case TR_AF_INET6: {
641            const unsigned char * address = (const unsigned char*)&a->addr.addr6;
642            return (address[0] == 0xFF) ||
643                   (memcmp(address, zeroes, 15) == 0 &&
644                    (address[15] == 0 || address[15] == 1)) ||
645                   /* Addresses outside of 2000::/3 are currently reserved,
646                      but might be allocated at some future time.  Since
647                      there are a lot of buggy peers pushing around such
648                      addresses over PEX, we reject them until the end of
649                      the 13th Baktun. */
650                   (tr_time() < 1356130800 && (address[0] & 0xE0) != 0x20);
651            break;
652        }
653
654        default:
655            return TRUE;
656    }
657}
658
659tr_bool
660tr_isValidPeerAddress( const tr_address * addr, tr_port port )
661{
662    return ( port != 0 )
663        && ( tr_isAddress( addr ) )
664        && ( !isIPv6LinkLocalAddress( addr ) )
665        && ( !isIPv4MappedAddress( addr ) )
666        && ( !isMartianAddr( addr ) );
667}
Note: See TracBrowser for help on using the repository browser.