source: trunk/libtransmission/net.c @ 10049

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

#2778 (IPv6 PEX accepts garbage addresses) -- accept petch from jch to reject IPv6 addresses outside of 2000::/3 until the end of the 13th Baktun

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