source: trunk/libtransmission/net.c @ 12225

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

(trunk libT) copyediting: remove a bunch of seemingly-unneeded network headers in net.[ch].

I'm less certain that these are unneeded because networking APIs seem to have more variation between platforms, but it's better to remove the cruft and then add back whatever headers $PLATFORM users complain about, than to not remove the cruft at all...

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