source: trunk/libtransmission/net.c @ 9748

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

(trunk libT) #2667 "Ignore martian addresses in LTEP messages" -- implemented for 1.80

  • Property svn:keywords set to Date Rev Author Id
File size: 17.4 KB
Line 
1/******************************************************************************
2 *
3 * $Id: net.c 9748 2009-12-14 02:07:47Z 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
243static tr_bool
244isMulticastAddress( const tr_address * addr )
245{
246    if( addr->type == TR_AF_INET && IN_MULTICAST( htonl( addr->addr.addr4.s_addr ) ) )
247        return TRUE;
248
249    if( addr->type == TR_AF_INET6 && ( addr->addr.addr6.s6_addr[0] == 0xff ) )
250        return TRUE;
251
252    return FALSE;
253}
254
255static TR_INLINE tr_bool
256isIPv4MappedOrCompatAddress( const tr_address * addr )
257{
258    if( addr->type == TR_AF_INET6 )
259    {
260        if( IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 ) ||
261            IN6_IS_ADDR_V4COMPAT( &addr->addr.addr6 ) )
262            return TRUE;
263    }
264    return FALSE;
265}
266
267static TR_INLINE tr_bool
268isIPv6LinkLocalAddress( const tr_address * addr )
269{
270    if( addr->type == TR_AF_INET6 &&
271        IN6_IS_ADDR_LINKLOCAL( &addr->addr.addr6 ) )
272        return TRUE;
273    return FALSE;
274}
275
276tr_bool
277tr_isValidPeerAddress( const tr_address * addr, tr_port port )
278{
279    if( isMulticastAddress( addr ) || isIPv6LinkLocalAddress( addr ) ||
280        isIPv4MappedOrCompatAddress( addr ) )
281        return FALSE;
282
283    if( port == 0 )
284        return FALSE;
285
286    return TRUE;
287}
288
289int
290tr_netOpenTCP( tr_session        * session,
291               const tr_address  * addr,
292               tr_port             port,
293               tr_bool             isSeed )
294{
295    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
296    int                     s;
297    struct sockaddr_storage sock;
298    socklen_t               addrlen;
299    const tr_address      * source_addr;
300    socklen_t               sourcelen;
301    struct sockaddr_storage source_sock;
302
303    assert( tr_isAddress( addr ) );
304
305    if( isMulticastAddress( addr ) || isIPv6LinkLocalAddress( addr ) )
306        return -EINVAL;
307
308    s = tr_fdSocketCreate( session, domains[addr->type], SOCK_STREAM );
309    if( s < 0 )
310        return -1;
311
312    /* seeds don't need much of a read buffer... */
313    if( isSeed ) {
314        int n = 8192;
315        if( setsockopt( s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n) ) )
316            tr_inf( "Unable to set SO_RCVBUF on socket %d: %s", s, tr_strerror( sockerrno ) );
317    }
318
319    if( evutil_make_socket_nonblocking( s ) < 0 ) {
320        tr_netClose( session, s );
321        return -1;
322    }
323
324    addrlen = setup_sockaddr( addr, port, &sock );
325
326    /* set source address */
327    source_addr = tr_sessionGetPublicAddress( session, addr->type );
328    assert( source_addr );
329    sourcelen = setup_sockaddr( source_addr, 0, &source_sock );
330    if( bind( s, ( struct sockaddr * ) &source_sock, sourcelen ) )
331    {
332        tr_err( _( "Couldn't set source address %s on %d: %s" ),
333                tr_ntop_non_ts( source_addr ), s, tr_strerror( errno ) );
334        return -errno;
335    }
336
337    if( ( connect( s, (struct sockaddr *) &sock,
338                  addrlen ) < 0 )
339#ifdef WIN32
340      && ( sockerrno != WSAEWOULDBLOCK )
341#endif
342      && ( sockerrno != EINPROGRESS ) )
343    {
344        int tmperrno;
345        tmperrno = sockerrno;
346        if( ( tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH )
347                || addr->type == TR_AF_INET )
348            tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
349                    s, tr_ntop_non_ts( addr ), (int)port, tmperrno,
350                    tr_strerror( tmperrno ) );
351        tr_netClose( session, s );
352        s = -tmperrno;
353    }
354
355    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
356               s, tr_peerIoAddrStr( addr, port ) );
357
358    return s;
359}
360
361static int
362tr_netBindTCPImpl( const tr_address * addr, tr_port port, tr_bool suppressMsgs, int * errOut )
363{
364    static const int domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
365    struct sockaddr_storage sock;
366    int fd;
367    int addrlen;
368    int optval;
369
370    assert( tr_isAddress( addr ) );
371
372    fd = socket( domains[addr->type], SOCK_STREAM, 0 );
373    if( fd < 0 ) {
374        *errOut = sockerrno;
375        return -1;
376    }
377
378    if( evutil_make_socket_nonblocking( fd ) < 0 ) {
379        *errOut = sockerrno;
380        tr_netCloseSocket( fd );
381        return -1;
382    }
383
384    optval = 1;
385    setsockopt( fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval) );
386    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
387
388#ifdef IPV6_V6ONLY
389    if( addr->type == TR_AF_INET6 )
390        if( setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof( optval ) ) == -1 )
391            if( sockerrno != ENOPROTOOPT ) { /* if the kernel doesn't support it, ignore it */
392                *errOut = sockerrno;
393                return -1;
394            }
395#endif
396
397    addrlen = setup_sockaddr( addr, htons( port ), &sock );
398    if( bind( fd, (struct sockaddr *) &sock, addrlen ) ) {
399        const int err = sockerrno;
400        if( !suppressMsgs )
401            tr_err( _( "Couldn't bind port %d on %s: %s" ),
402                    port, tr_ntop_non_ts( addr ), tr_strerror( err ) );
403        tr_netCloseSocket( fd );
404        *errOut = err;
405        return -1;
406    }
407
408    if( !suppressMsgs )
409        tr_dbg( "Bound socket %d to port %d on %s", fd, port, tr_ntop_non_ts( addr ) );
410
411    if( listen( fd, 128 ) == -1 ) {
412        *errOut = sockerrno;
413        tr_netCloseSocket( fd );
414        return -1;
415    }
416
417    return fd;
418}
419
420int
421tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
422{
423    int unused;
424    return tr_netBindTCPImpl( addr, port, suppressMsgs, &unused );
425}
426
427tr_bool
428tr_net_hasIPv6( tr_port port )
429{
430    static tr_bool result = FALSE;
431    static tr_bool alreadyDone = FALSE;
432
433    if( !alreadyDone )
434    {
435        int err;
436        int fd = tr_netBindTCPImpl( &tr_in6addr_any, port, TRUE, &err );
437        if( fd >= 0 || err != EAFNOSUPPORT ) /* we support ipv6 */
438            result = TRUE;
439        if( fd >= 0 )
440            tr_netCloseSocket( fd );
441        alreadyDone = TRUE;
442    }
443
444    return result;
445}
446
447int
448tr_netAccept( tr_session  * session,
449              int           b,
450              tr_address  * addr,
451              tr_port     * port )
452{
453    int fd = tr_fdSocketAccept( session, b, addr, port );
454
455    if( fd>=0 && evutil_make_socket_nonblocking(fd)<0 ) {
456        tr_netClose( session, fd );
457        fd = -1;
458    }
459
460    return fd;
461}
462
463void
464tr_netCloseSocket( int fd )
465{
466    EVUTIL_CLOSESOCKET( fd );
467}
468
469void
470tr_netClose( tr_session * session, int s )
471{
472    tr_fdSocketClose( session, s );
473}
474
475/*
476   get_source_address(), get_name_source_address(), and
477   global_unicast_address() were written by Juliusz Chroboczek,
478   and are covered under the same license as dht.c.
479   Please feel free to copy them into your software
480   if it can help unbreaking the double-stack Internet. */
481
482/* Get the source address used for a given destination address.  Since
483   there is no official interface to get this information, we create
484   a connected UDP socket (connected UDP... hmm...) and check its source
485   address. */
486static int
487get_source_address( const struct sockaddr  * dst,
488                    socklen_t                dst_len,
489                    struct sockaddr        * src,
490                    socklen_t              * src_len )
491{
492    int s, rc, save;
493
494    s = socket(dst->sa_family, SOCK_DGRAM, 0);
495    if(s < 0)
496        goto fail;
497
498    /* Since it's a UDP socket, this doesn't actually send any packets. */
499    rc = connect(s, dst, dst_len);
500    if(rc < 0)
501        goto fail;
502
503    rc = getsockname(s, src, src_len);
504    if(rc < 0)
505        goto fail;
506
507    EVUTIL_CLOSESOCKET( s );
508
509    return rc;
510
511 fail:
512    save = errno;
513    EVUTIL_CLOSESOCKET( s );
514    errno = save;
515    return -1;
516}
517
518/* Like above, but for a given DNS name. */
519static int
520get_name_source_address(int af, const char *name,
521                        struct sockaddr *src, socklen_t *src_len)
522{
523    struct addrinfo hints, *info, *infop;
524    int rc;
525
526    memset(&hints, 0, sizeof(hints));
527    hints.ai_family = af;
528    hints.ai_socktype = SOCK_DGRAM;
529
530    rc = getaddrinfo(name, "80", &hints, &info);
531    if(rc != 0) {
532        errno = ENOENT;
533        return -1;
534    }
535
536    rc = -1;
537    errno = ENOENT;
538    infop = info;
539    while(infop) {
540        if(infop->ai_addr->sa_family == af) {
541            rc = get_source_address(infop->ai_addr, infop->ai_addrlen,
542                                    src, src_len);
543            if(rc >= 0)
544                break;
545        }
546        infop = infop->ai_next;
547    }
548
549    freeaddrinfo(info);
550    return rc;
551}
552
553/* We all hate NATs. */
554static int
555global_unicast_address(struct sockaddr *sa)
556{
557    if(sa->sa_family == AF_INET) {
558        const unsigned char *a =
559            (unsigned char*)&((struct sockaddr_in*)sa)->sin_addr;
560        if(a[0] == 0 || a[0] == 127 || a[0] >= 224 ||
561           a[0] == 10 || (a[0] == 172 && a[1] >= 16 && a[1] <= 31) ||
562           (a[0] == 192 && a[1] == 168))
563            return 0;
564        return 1;
565    } else if(sa->sa_family == AF_INET6) {
566        const unsigned char *a =
567            (unsigned char*)&((struct sockaddr_in6*)sa)->sin6_addr;
568        /* 2000::/3 */
569        return (a[0] & 0xE0) == 0x20;
570    } else {
571        errno = EAFNOSUPPORT;
572        return -1;
573    }
574}
575
576int
577tr_globalAddress( int af, void *addr, int *addr_len )
578{
579    struct sockaddr_storage ss;
580    socklen_t ss_len = sizeof(ss);
581    int rc;
582
583    /* This should be a name with both IPv4 and IPv6 addresses. */
584    rc = get_name_source_address( af, "www.transmissionbt.com",
585                                  (struct sockaddr*)&ss, &ss_len );
586    /* In case Charles removes IPv6 from his website. */
587    if( rc < 0 )
588        rc = get_name_source_address(  af, "www.ietf.org",
589                                      (struct sockaddr*)&ss, &ss_len );
590
591    if( rc < 0 )
592        return -1;
593
594    if( !global_unicast_address( (struct sockaddr*)&ss) )
595        return -1;
596
597    switch(af) {
598    case AF_INET:
599        if(*addr_len < 4)
600            return -1;
601        memcpy(addr, &((struct sockaddr_in*)&ss)->sin_addr, 4);
602        *addr_len = 4;
603        return 1;
604    case AF_INET6:
605        if(*addr_len < 16)
606            return -1;
607        memcpy(addr, &((struct sockaddr_in6*)&ss)->sin6_addr, 16);
608        *addr_len = 16;
609        return 1;
610    default:
611        return -1;
612    }
613}
614
615/* Return our global IPv6 address, with caching. */
616
617const unsigned char *
618tr_globalIPv6( void )
619{
620    static unsigned char ipv6[16];
621    static time_t last_time = 0;
622    static int have_ipv6 = 0;
623    const time_t now = tr_time( );
624
625    /* Re-check every half hour */
626    if( last_time < now - 1800 )
627    {
628        int addrlen = 16;
629        const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen );
630        have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 );
631        last_time = now;
632    }
633
634    return have_ipv6 ? ipv6 : NULL;
635}
636
637int
638tr_isMartian( int af, const unsigned char * address )
639{
640    static const unsigned char v4prefix[16] =
641        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
642    static const unsigned char zeroes[16] =
643        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
644
645    switch( af )
646    {
647        case AF_INET:
648            return (address[0] == 0) ||
649                   (address[0] == 127) ||
650                   ((address[0] & 0xE0) == 0xE0);
651
652        case AF_INET6:
653            return (address[0] == 0xFF) ||
654                   (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
655                   (memcmp(address, zeroes, 15) == 0 && (address[15] == 0 || address[15] == 1)) ||
656                   (memcmp(address, v4prefix, 12) == 0);
657
658        default:
659            return FALSE;
660    }
661}
Note: See TracBrowser for help on using the repository browser.