package axel tags 525290 + patch thanks Let me submit a patch to make axel able to use IPv6 for content transport, this is a rewrite of tcp_connect() in axel-2.4/tcp.c so that the binary freely can change between IPv4 and IPv6.
The lookup function get_if_ip() is only prepared to ease migration to IPv6 lookups. The reason is that I am presently not convinced that the 'struct ifreq' handles IPv6 properly. My knowledge on this does not suffice momentarily. In summary, as long as the configuration file does not specify 'interface = this0', then the use of IPv6 or IPv4 depends on the target, not on Axel. In case a configuration is active, only IPv4 works presently, because that is the address family returned by get_if_ip() at the present time, even with this patch applied. I will work further on this matter. Best regards, Mats Erik Andersson, fil. dr
Description: Implement IPv6 prototocol support. The transport sockets are reimplemented to fully accept address family IPv4 as well as IPv6. . The lookup function get_if_ip() is slightly altered to ease a later migration for supporting both families. Author: Mats Erik Andersson <deb...@gisladisker.se> Forwarded: yes Last-Update: 2010-04-15 --- axel-2.4.orig/tcp.c 2009-04-27 16:19:03.000000000 +0200 +++ axel-2.4/tcp.c 2010-04-15 13:47:51.000000000 +0200 @@ -25,59 +25,113 @@ #include "axel.h" +#define LOCAL_DEBUG 0 + /* Get a TCP connection */ int tcp_connect( char *hostname, int port, char *local_if ) { - struct hostent *host = NULL; - struct sockaddr_in addr; - struct sockaddr_in local; - int fd; + struct addrinfo hints, *ai, *aiptr; + struct sockaddr_storage local; + socklen_t local_addrlen = 0; + int fd, rc, do_bind = 0; + char portstr[12]; -#ifdef DEBUG +#if defined(DEBUG) || LOCAL_DEBUG + struct sockaddr_in *local_sa4 = (struct sockaddr_in *) &local; + struct sockaddr_in6 *local_sa6 = (struct sockaddr_in6 *) &local; socklen_t i = sizeof( local ); fprintf( stderr, "tcp_connect( %s, %i ) = ", hostname, port ); #endif - - /* Why this loop? Because the call might return an empty record. - At least it very rarely does, on my system... */ - for( fd = 0; fd < 5; fd ++ ) - { - if( ( host = gethostbyname( hostname ) ) == NULL ) - return( -1 ); - if( *host->h_name ) break; - } - if( !host || !host->h_name || !*host->h_name ) - return( -1 ); - - if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) - return( -1 ); - + + /* First check the validity of any local part. */ if( local_if && *local_if ) { - local.sin_family = AF_INET; - local.sin_port = 0; - local.sin_addr.s_addr = inet_addr( local_if ); - if( bind( fd, (struct sockaddr *) &local, sizeof( struct sockaddr_in ) ) == -1 ) + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if( ( rc = getaddrinfo(local_if, NULL, &hints, &ai) ) ) + return -1; + + for( aiptr = ai; aiptr; aiptr = aiptr->ai_next ) { + if( (fd = socket(aiptr->ai_family, aiptr->ai_socktype, + aiptr->ai_protocol) ) < 0 ) + continue; + + if( bind( fd, (struct sockaddr *) &local, aiptr->ai_addrlen) + == -1 ) + { + close( fd ); + continue; + } + /* Success */ close( fd ); + break; + } /* Looping over candidates in ai. */ + + if( aiptr == NULL ) + { + /* Reached end of candidate list. No success! */ + freeaddrinfo(ai); return( -1 ); } - } - - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - addr.sin_addr = *( (struct in_addr *) host->h_addr ); - - if( connect( fd, (struct sockaddr *) &addr, sizeof( struct sockaddr_in ) ) == -1 ) + + /* Access was granted to local address. */ + do_bind = 1; + local_addrlen = aiptr->ai_addrlen; + freeaddrinfo(ai); + } /* Lookup of local address for binding. */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + snprintf(portstr, sizeof(portstr)-1, "%d", port); + + if( ( rc = getaddrinfo(hostname, portstr, &hints, &ai) ) ) { - close( fd ); + /* Failed host lookup. */ return( -1 ); } - -#ifdef DEBUG - getsockname( fd, &local, &i ); - fprintf( stderr, "%i\n", ntohs( local.sin_port ) ); + + /* Successfully resolved hostname. Loop through candidates. */ + for( aiptr = ai; aiptr; aiptr = aiptr->ai_next ) + { + if( ( fd = socket( aiptr->ai_family, aiptr->ai_socktype, + aiptr->ai_protocol) ) < 0 ) + continue; + + if( do_bind && ( bind( fd, (struct sockaddr *) &local, + local_addrlen) == -1 ) ) + { + close( fd ); + continue; + } + + if( connect( fd, aiptr->ai_addr, aiptr->ai_addrlen) < 0 ) + { + close( fd ); + continue; + } + + break; + } /* Looping over candidates in ai. */ + + if( aiptr == NULL ) + { + /* No answer. */ + freeaddrinfo(ai); + return -1; + } + +#if defined(DEBUG) || LOCAL_DEBUG + getsockname( fd, (struct sockaddr *) &local, &i ); + fprintf( stderr, "%i\n", + ntohs( (local.ss_family == AF_INET6) ? local_sa6->sin6_port + : local_sa4->sin_port ) ); #endif return( fd ); @@ -91,11 +145,16 @@ int get_if_ip( char *iface, char *ip ) memset( &ifr, 0, sizeof( struct ifreq ) ); strcpy( ifr.ifr_name, iface ); - ifr.ifr_addr.sa_family = AF_INET; + ifr.ifr_addr.sa_family = AF_UNSPEC; if( ioctl( fd, SIOCGIFADDR, &ifr ) == 0 ) { struct sockaddr_in *x = (struct sockaddr_in *) &ifr.ifr_addr; - strcpy( ip, inet_ntoa( x->sin_addr ) ); + inet_ntop( ifr.ifr_addr.sa_family, &x->sin_addr, + ip, INET6_ADDRSTRLEN); /* << MAX_STRING in axel.h */ + close( fd ); +#if defined(DEBUG) || LOCAL_DEBUG + fprintf(stderr, "get_if_ip() succeded with %s\n", ip); +#endif return( 1 ); } else
signature.asc
Description: Digital signature