Changeset 9499


Ignore:
Timestamp:
Nov 9, 2009, 5:45:16 AM (12 years ago)
Author:
charles
Message:

(trunk libT) #2502: announce own IPv6 address to peers

Location:
trunk/libtransmission
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/net.c

    r9485 r9499  
    11/******************************************************************************
     2 *
    23 * $Id$
    34 *
     
    463464    tr_fdSocketClose( session, s );
    464465}
     466
     467/*
     468   get_source_address(), get_name_source_address(), and
     469   global_unicast_address() were written by Juliusz Chroboczek,
     470   and are covered under the same license as dht.c.
     471   Please feel free to copy them into your software
     472   if it can help unbreaking the double-stack Internet. */
     473
     474/* Get the source address used for a given destination address.  Since
     475   there is no official interface to get this information, we create
     476   a connected UDP socket (connected UDP... hmm...) and check its source
     477   address. */
     478static int
     479get_source_address( const struct sockaddr  * dst,
     480                    socklen_t                dst_len,
     481                    struct sockaddr        * src,
     482                    socklen_t              * src_len )
     483{
     484    int s, rc, save;
     485
     486    s = socket(dst->sa_family, SOCK_DGRAM, 0);
     487    if(s < 0)
     488        goto fail;
     489
     490    /* Since it's a UDP socket, this doesn't actually send any packets. */
     491    rc = connect(s, dst, dst_len);
     492    if(rc < 0)
     493        goto fail;
     494
     495    rc = getsockname(s, src, src_len);
     496    if(rc < 0)
     497        goto fail;
     498
     499    EVUTIL_CLOSESOCKET( s );
     500
     501    return rc;
     502
     503 fail:
     504    save = errno;
     505    EVUTIL_CLOSESOCKET( s );
     506    errno = save;
     507    return -1;
     508}
     509
     510/* Like above, but for a given DNS name. */
     511static int
     512get_name_source_address(int af, const char *name,
     513                        struct sockaddr *src, socklen_t *src_len)
     514{
     515    struct addrinfo hints, *info, *infop;
     516    int rc;
     517
     518    memset(&hints, 0, sizeof(hints));
     519    hints.ai_family = af;
     520    hints.ai_socktype = SOCK_DGRAM;
     521
     522    rc = getaddrinfo(name, NULL, &hints, &info);
     523    if(rc != 0) {
     524        errno = ENOENT;
     525        return -1;
     526    }
     527
     528    rc = -1;
     529    errno = ENOENT;
     530    infop = info;
     531    while(infop) {
     532        if(infop->ai_addr->sa_family == af) {
     533            rc = get_source_address(infop->ai_addr, infop->ai_addrlen,
     534                                    src, src_len);
     535            if(rc >= 0)
     536                break;
     537        }
     538        infop = infop->ai_next;
     539    }
     540
     541    freeaddrinfo(info);
     542    return rc;
     543}
     544
     545/* We all hate NATs. */
     546static int
     547global_unicast_address(struct sockaddr *sa)
     548{
     549    if(sa->sa_family == AF_INET) {
     550        const unsigned char *a =
     551            (unsigned char*)&((struct sockaddr_in*)sa)->sin_addr;
     552        if(a[0] == 0 || a[0] == 127 || a[0] >= 224 ||
     553           a[0] == 10 || (a[0] == 172 && a[1] >= 16 && a[1] <= 31) ||
     554           (a[0] == 192 && a[1] == 168))
     555            return 0;
     556        return 1;
     557    } else if(sa->sa_family == AF_INET6) {
     558        const unsigned char *a =
     559            (unsigned char*)&((struct sockaddr_in6*)sa)->sin6_addr;
     560        /* 2000::/3 */
     561        return (a[0] & 0xE0) == 0x20;
     562    } else {
     563        errno = EAFNOSUPPORT;
     564        return -1;
     565    }
     566}
     567
     568int
     569tr_globalAddress( int af, void *addr, int *addr_len )
     570{
     571    struct sockaddr_storage ss;
     572    socklen_t ss_len = sizeof(ss);
     573    int rc;
     574
     575    /* This should be a name with both IPv4 and IPv6 addresses. */
     576    rc = get_name_source_address( af, "www.transmissionbt.com",
     577                                  (struct sockaddr*)&ss, &ss_len );
     578    /* In case Charles removes IPv6 from his website. */
     579    if( rc < 0 )
     580        rc = get_name_source_address(  af, "www.ietf.org",
     581                                      (struct sockaddr*)&ss, &ss_len );
     582
     583    if( rc < 0 )
     584        return -1;
     585
     586    if( !global_unicast_address( (struct sockaddr*)&ss) )
     587        return -1;
     588
     589    switch(af) {
     590    case AF_INET:
     591        if(*addr_len < 4)
     592            return -1;
     593        memcpy(addr, &((struct sockaddr_in*)&ss)->sin_addr, 4);
     594        *addr_len = 4;
     595        return 1;
     596    case AF_INET6:
     597        if(*addr_len < 16)
     598            return -1;
     599        memcpy(addr, &((struct sockaddr_in6*)&ss)->sin6_addr, 16);
     600        *addr_len = 16;
     601        return 1;
     602    default:
     603        return -1;
     604    }
     605}
  • trunk/libtransmission/net.h

    r9417 r9499  
    121121void tr_netInit( void );
    122122
     123int tr_globalAddress(int af, void *addr, int *addr_len);
     124
    123125#endif /* _TR_NET_H_ */
  • trunk/libtransmission/peer-msgs.c

    r9494 r9499  
    808808**/
    809809
     810/* Return our global IPv6 address, with caching. */
     811
     812static const unsigned char *
     813globalIPv6( void )
     814{
     815    static unsigned char ipv6[16];
     816    static time_t last_time = 0;
     817    static int have_ipv6 = 0;
     818    const time_t now = time( NULL );
     819
     820    /* Re-check every half hour */
     821    if( last_time < now - 1800 )
     822    {
     823        int addrlen = 16;
     824        const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen );
     825        have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 );
     826        last_time = now;
     827    }
     828
     829    return have_ipv6 ? ipv6 : NULL;
     830}
     831
    810832static void
    811833sendLtepHandshake( tr_peermsgs * msgs )
     
    816838    int pex;
    817839    struct evbuffer * out = msgs->outMessages;
     840    const unsigned char * ipv6 = globalIPv6();
    818841
    819842    if( msgs->clientSentLtepHandshake )
     
    831854        pex = 1;
    832855
    833     tr_bencInitDict( &val, 5 );
     856    tr_bencInitDict( &val, 7 );
    834857    tr_bencDictAddInt( &val, "e", getSession(msgs)->encryptionMode != TR_CLEAR_PREFERRED );
     858    if( ipv6 )
     859        tr_bencDictAddRaw( &val, "ipv6", ipv6, 16 );
    835860    tr_bencDictAddInt( &val, "p", tr_sessionGetPeerPort( getSession(msgs) ) );
    836861    tr_bencDictAddInt( &val, "reqq", REQQ );
     
    862887    tr_benc   val, * sub;
    863888    uint8_t * tmp = tr_new( uint8_t, len );
     889    const uint8_t *addr;
     890    size_t addr_len;
     891    tr_pex pex;
     892
     893    memset( &pex, 0, sizeof( tr_pex ) );
    864894
    865895    tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, len );
     
    876906
    877907    /* does the peer prefer encrypted connections? */
    878     if( tr_bencDictFindInt( &val, "e", &i ) )
     908    if( tr_bencDictFindInt( &val, "e", &i ) ) {
    879909        msgs->peer->encryption_preference = i ? ENCRYPTION_PREFERENCE_YES
    880910                                              : ENCRYPTION_PREFERENCE_NO;
     911        if( i )
     912            pex.flags |= ADDED_F_ENCRYPTION_FLAG;
     913    }
    881914
    882915    /* check supported messages for utorrent pex */
     
    891924
    892925    /* look for upload_only (BEP 21) */
    893     if( tr_bencDictFindInt( &val, "upload_only", &i ) )
     926    if( tr_bencDictFindInt( &val, "upload_only", &i ) ) {
    894927        fireUploadOnly( msgs, i!=0 );
     928        if( i )
     929            pex.flags |= ADDED_F_SEED_FLAG;
     930    }
    895931
    896932    /* get peer's listening port */
    897933    if( tr_bencDictFindInt( &val, "p", &i ) ) {
    898934        fireClientGotPort( msgs, (tr_port)i );
     935        pex.port = htons( (uint16_t)i );
    899936        dbgmsg( msgs, "peer's port is now %d", (int)i );
     937    }
     938
     939    if( tr_bencDictFindRaw( &val, "ipv4", &addr, &addr_len) && addr_len == 4 ) {
     940        pex.addr.type = TR_AF_INET;
     941        memcpy( &pex.addr.addr.addr4, addr, 4 );
     942        tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_ALT, &pex );
     943    }
     944 
     945    if( tr_bencDictFindRaw( &val, "ipv6", &addr, &addr_len) && addr_len == 16 ) {
     946        pex.addr.type = TR_AF_INET6;
     947        memcpy( &pex.addr.addr.addr6, addr, 16 );
     948        tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_ALT, &pex );
    900949    }
    901950
     
    18861935        dbgmsg(
    18871936            msgs,
    1888             "pex: old peer count %d, new peer count %d, added %d, removed %d",
    1889             msgs->pexCount, newCount + newCount6,
    1890             diffs.addedCount + diffs6.addedCount,
    1891             diffs.droppedCount + diffs6.droppedCount );
     1937            "pex: old peer count %d+%d, new peer count %d+%d, "
     1938            "added %d+%d, removed %d+%d",
     1939            msgs->pexCount, msgs->pexCount6, newCount, newCount6,
     1940            diffs.addedCount, diffs6.addedCount,
     1941            diffs.droppedCount, diffs6.droppedCount );
    18921942
    18931943        if( !diffs.addedCount && !diffs.droppedCount && !diffs6.addedCount &&
  • trunk/libtransmission/transmission.h

    r9404 r9499  
    15721572    TR_PEER_FROM_CACHE     = 3,  /* peers read from the peer cache */
    15731573    TR_PEER_FROM_PEX       = 4,  /* peers discovered via PEX */
     1574    TR_PEER_FROM_ALT       = 5,  /* alternate peer address */
    15741575    TR_PEER_FROM__MAX
    15751576};
Note: See TracChangeset for help on using the changeset viewer.