Loading CHANGES +6 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,12 @@ Changelog Daniel Fandrich (9 Oct 2008) - Fixed the --interface option to work with IPv6 connections on glibc systems supporting getifaddrs(). Also fixed a problem where an IPv6 address could be chosen instead of an IPv4 one for --interface when it involved a name lookup. Daniel Fandrich (8 Oct 2008) - Added tests 1082 through 1085 to test symbolic --interface parameters Loading RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ This release includes the following changes: o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them o configure --disable-proxy disables proxy o Added CURLOPT_USERNAME and CURLOPT_PASSWORD o --interface now works with IPv6 connections on glibc systems This release includes the following bugfixes: Loading configure.ac +1 −0 Original line number Diff line number Diff line Loading @@ -2061,6 +2061,7 @@ AC_CHECK_FUNCS([basename \ fork \ geteuid \ gethostbyaddr \ getifaddrs \ getpass_r \ getppid \ getprotobyname \ Loading lib/connect.c +58 −53 Original line number Diff line number Diff line Loading @@ -284,15 +284,16 @@ int waitconnect(curl_socket_t sockfd, /* socket */ } static CURLcode bindlocal(struct connectdata *conn, curl_socket_t sockfd) curl_socket_t sockfd, int af) { #ifdef ENABLE_IPV6 char ipv6_addr[16]; #endif struct SessionHandle *data = conn->data; struct sockaddr_in me; #ifdef ENABLE_IPV6 struct sockaddr_in6 me6; #endif struct sockaddr *sock = NULL; /* bind to this address */ socklen_t socksize; /* size of the data sock points to */ socklen_t socksize = 0; /* size of the data sock points to */ struct Curl_dns_entry *h=NULL; unsigned short port = data->set.localport; /* use this port number, 0 for "random" */ /* how many port numbers to try to bind to, increasing one at a time */ Loading @@ -303,20 +304,13 @@ static CURLcode bindlocal(struct connectdata *conn, * Select device to bind socket to *************************************************************/ if(dev && (strlen(dev)<255) ) { struct Curl_dns_entry *h=NULL; char myhost[256] = ""; in_addr_t in; int rc; bool was_iface = FALSE; int in6 = -1; /* First check if the given name is an IP address */ in=inet_addr((char *) dev); if((in == CURL_INADDR_NONE) && Curl_if2ip(dev, myhost, sizeof(myhost))) { if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) { /* * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer * We now have the numerical IP address in the 'myhost' buffer */ rc = Curl_resolv(conn, myhost, 0, &h); if(rc == CURLRESOLV_PENDING) Loading @@ -324,7 +318,6 @@ static CURLcode bindlocal(struct connectdata *conn, if(h) { was_iface = TRUE; Curl_resolv_unlock(data, h); } } Loading @@ -333,22 +326,30 @@ static CURLcode bindlocal(struct connectdata *conn, * This was not an interface, resolve the name as a host name * or IP number */ /* * Temporarily force name resolution to use only the address type * of the connection. The resolve functions should really be changed * to take a type parameter instead. */ long ipver = data->set.ip_version; if (af == AF_INET) data->set.ip_version = CURL_IPRESOLVE_V4; else if (af == AF_INET6) data->set.ip_version = CURL_IPRESOLVE_V6; rc = Curl_resolv(conn, dev, 0, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_wait_for_resolv(conn, &h); data->set.ip_version = ipver; if(h) { if(in == CURL_INADDR_NONE) /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ Curl_printable_address(h->addr, myhost, sizeof myhost); else /* we know data->set.device is shorter than the myhost array */ strcpy(myhost, dev); Curl_resolv_unlock(data, h); } } if(! *myhost) { if(!*myhost || !h) { /* need to fix this h=Curl_gethost(data, getmyhost(*myhost,sizeof(myhost)), Loading @@ -356,11 +357,16 @@ static CURLcode bindlocal(struct connectdata *conn, sizeof(hostent_buf)); */ failf(data, "Couldn't bind to '%s'", dev); if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } infof(data, "Bind local address to %s\n", myhost); sock = h->addr->ai_addr; socksize = h->addr->ai_addrlen; #ifdef SO_BINDTODEVICE /* I am not sure any other OSs than Linux that provide this feature, and * at the least I cannot test. --Ben Loading @@ -378,35 +384,19 @@ static CURLcode bindlocal(struct connectdata *conn, dev, strlen(dev)+1) != 0) { /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", sockfd, dev, Curl_strerror(SOCKERRNO)); */ infof(data, "SO_BINDTODEVICE %s failed\n", dev); int error = ERRNO; infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s; will do regular bind\n", dev, error, Curl_strerror(conn, error)); /* This is typically "errno 1, error: Operation not permitted" if you're not running as root or another suitable privileged user */ } } #endif in=inet_addr(myhost); #ifdef ENABLE_IPV6 in6 = Curl_inet_pton (AF_INET6, myhost, (void *)&ipv6_addr); #endif if(CURL_INADDR_NONE == in && -1 == in6) { failf(data,"couldn't find my own IP address (%s)", myhost); return CURLE_INTERFACE_FAILED; } /* end of inet_addr */ if( h ) { Curl_addrinfo *addr = h->addr; sock = addr->ai_addr; socksize = addr->ai_addrlen; } else return CURLE_INTERFACE_FAILED; } else if(port) { /* if a local port number is requested but no local IP, extract the address from the socket */ if(af == AF_INET) { memset(&me, 0, sizeof(struct sockaddr)); me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; Loading @@ -415,6 +405,17 @@ static CURLcode bindlocal(struct connectdata *conn, socksize = sizeof(struct sockaddr); } #ifdef ENABLE_IPV6 else { /* AF_INET6 */ memset(&me6, 0, sizeof(struct sockaddr)); me6.sin6_family = AF_INET6; me6.sin6_addr = in6addr_any; sock = (struct sockaddr *)&me6; socksize = sizeof(struct sockaddr); } #endif } else /* no local kind of binding was requested */ return CURLE_OK; Loading @@ -432,11 +433,11 @@ static CURLcode bindlocal(struct connectdata *conn, if( bind(sockfd, sock, socksize) >= 0) { /* we succeeded to bind */ struct Curl_sockaddr_storage add; socklen_t size; size = sizeof(add); socklen_t size = sizeof(add); if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { failf(data, "getsockname() failed"); if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } /* We re-use/clobber the port variable here below */ Loading @@ -448,6 +449,8 @@ static CURLcode bindlocal(struct connectdata *conn, #endif infof(data, "Local port: %d\n", port); conn->bits.bound = TRUE; if(h) Curl_resolv_unlock(data, h); return CURLE_OK; } if(--portnum > 0) { Loading @@ -461,8 +464,10 @@ static CURLcode bindlocal(struct connectdata *conn, data->state.os_errno = SOCKERRNO; failf(data, "bind failure: %s", Curl_strerror(conn, data->state.os_errno)); return CURLE_INTERFACE_FAILED; if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } /* Loading Loading @@ -822,7 +827,7 @@ singleipconnect(struct connectdata *conn, } /* possibly bind the local end to an IP, interface or port */ res = bindlocal(conn, sockfd); res = bindlocal(conn, sockfd, addr->family); if(res) { sclose(sockfd); /* close socket and bail out */ return CURL_SOCKET_BAD; Loading lib/ftp.c +6 −6 Original line number Diff line number Diff line Loading @@ -892,7 +892,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(data->set.str[STRING_FTPPORT] && (strlen(data->set.str[STRING_FTPPORT]) > 1)) { /* attempt to get the address of the given interface name */ if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) if(!Curl_if2ip(conn->ip_addr->ai_family, data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) /* not an interface, use the given string as host name instead */ host = data->set.str[STRING_FTPPORT]; else Loading Loading @@ -964,8 +965,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* It failed. Bind the address used for the control connection instead */ sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)sa, &sslen)) { if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); sclose(portsock); Loading @@ -973,7 +973,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, } /* set port number to zero to make bind() pick "any" */ if(((struct sockaddr *)sa)->sa_family == AF_INET) if(sa->sa_family == AF_INET) ((struct sockaddr_in *)sa)->sin_port=0; else ((struct sockaddr_in6 *)sa)->sin6_port =0; Loading @@ -981,7 +981,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(sslen > (socklen_t)sizeof(ss)) sslen = sizeof(ss); if(bind(portsock, (struct sockaddr *)sa, sslen)) { if(bind(portsock, sa, sslen)) { failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO)); sclose(portsock); return CURLE_FTP_PORT_FAILED; Loading Loading @@ -1112,7 +1112,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* this is an IPv4 address */ addr = Curl_ip2addr(in, ftpportstr, 0); else { if(Curl_if2ip(ftpportstr, myhost, sizeof(myhost))) { if(Curl_if2ip(AF_INET, ftpportstr, myhost, sizeof(myhost))) { /* The interface to IP conversion provided a dotted address */ in=inet_addr(myhost); addr = Curl_ip2addr(in, myhost, 0); Loading Loading
CHANGES +6 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,12 @@ Changelog Daniel Fandrich (9 Oct 2008) - Fixed the --interface option to work with IPv6 connections on glibc systems supporting getifaddrs(). Also fixed a problem where an IPv6 address could be chosen instead of an IPv4 one for --interface when it involved a name lookup. Daniel Fandrich (8 Oct 2008) - Added tests 1082 through 1085 to test symbolic --interface parameters Loading
RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ This release includes the following changes: o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them o configure --disable-proxy disables proxy o Added CURLOPT_USERNAME and CURLOPT_PASSWORD o --interface now works with IPv6 connections on glibc systems This release includes the following bugfixes: Loading
configure.ac +1 −0 Original line number Diff line number Diff line Loading @@ -2061,6 +2061,7 @@ AC_CHECK_FUNCS([basename \ fork \ geteuid \ gethostbyaddr \ getifaddrs \ getpass_r \ getppid \ getprotobyname \ Loading
lib/connect.c +58 −53 Original line number Diff line number Diff line Loading @@ -284,15 +284,16 @@ int waitconnect(curl_socket_t sockfd, /* socket */ } static CURLcode bindlocal(struct connectdata *conn, curl_socket_t sockfd) curl_socket_t sockfd, int af) { #ifdef ENABLE_IPV6 char ipv6_addr[16]; #endif struct SessionHandle *data = conn->data; struct sockaddr_in me; #ifdef ENABLE_IPV6 struct sockaddr_in6 me6; #endif struct sockaddr *sock = NULL; /* bind to this address */ socklen_t socksize; /* size of the data sock points to */ socklen_t socksize = 0; /* size of the data sock points to */ struct Curl_dns_entry *h=NULL; unsigned short port = data->set.localport; /* use this port number, 0 for "random" */ /* how many port numbers to try to bind to, increasing one at a time */ Loading @@ -303,20 +304,13 @@ static CURLcode bindlocal(struct connectdata *conn, * Select device to bind socket to *************************************************************/ if(dev && (strlen(dev)<255) ) { struct Curl_dns_entry *h=NULL; char myhost[256] = ""; in_addr_t in; int rc; bool was_iface = FALSE; int in6 = -1; /* First check if the given name is an IP address */ in=inet_addr((char *) dev); if((in == CURL_INADDR_NONE) && Curl_if2ip(dev, myhost, sizeof(myhost))) { if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) { /* * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer * We now have the numerical IP address in the 'myhost' buffer */ rc = Curl_resolv(conn, myhost, 0, &h); if(rc == CURLRESOLV_PENDING) Loading @@ -324,7 +318,6 @@ static CURLcode bindlocal(struct connectdata *conn, if(h) { was_iface = TRUE; Curl_resolv_unlock(data, h); } } Loading @@ -333,22 +326,30 @@ static CURLcode bindlocal(struct connectdata *conn, * This was not an interface, resolve the name as a host name * or IP number */ /* * Temporarily force name resolution to use only the address type * of the connection. The resolve functions should really be changed * to take a type parameter instead. */ long ipver = data->set.ip_version; if (af == AF_INET) data->set.ip_version = CURL_IPRESOLVE_V4; else if (af == AF_INET6) data->set.ip_version = CURL_IPRESOLVE_V6; rc = Curl_resolv(conn, dev, 0, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_wait_for_resolv(conn, &h); data->set.ip_version = ipver; if(h) { if(in == CURL_INADDR_NONE) /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ Curl_printable_address(h->addr, myhost, sizeof myhost); else /* we know data->set.device is shorter than the myhost array */ strcpy(myhost, dev); Curl_resolv_unlock(data, h); } } if(! *myhost) { if(!*myhost || !h) { /* need to fix this h=Curl_gethost(data, getmyhost(*myhost,sizeof(myhost)), Loading @@ -356,11 +357,16 @@ static CURLcode bindlocal(struct connectdata *conn, sizeof(hostent_buf)); */ failf(data, "Couldn't bind to '%s'", dev); if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } infof(data, "Bind local address to %s\n", myhost); sock = h->addr->ai_addr; socksize = h->addr->ai_addrlen; #ifdef SO_BINDTODEVICE /* I am not sure any other OSs than Linux that provide this feature, and * at the least I cannot test. --Ben Loading @@ -378,35 +384,19 @@ static CURLcode bindlocal(struct connectdata *conn, dev, strlen(dev)+1) != 0) { /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", sockfd, dev, Curl_strerror(SOCKERRNO)); */ infof(data, "SO_BINDTODEVICE %s failed\n", dev); int error = ERRNO; infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s; will do regular bind\n", dev, error, Curl_strerror(conn, error)); /* This is typically "errno 1, error: Operation not permitted" if you're not running as root or another suitable privileged user */ } } #endif in=inet_addr(myhost); #ifdef ENABLE_IPV6 in6 = Curl_inet_pton (AF_INET6, myhost, (void *)&ipv6_addr); #endif if(CURL_INADDR_NONE == in && -1 == in6) { failf(data,"couldn't find my own IP address (%s)", myhost); return CURLE_INTERFACE_FAILED; } /* end of inet_addr */ if( h ) { Curl_addrinfo *addr = h->addr; sock = addr->ai_addr; socksize = addr->ai_addrlen; } else return CURLE_INTERFACE_FAILED; } else if(port) { /* if a local port number is requested but no local IP, extract the address from the socket */ if(af == AF_INET) { memset(&me, 0, sizeof(struct sockaddr)); me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; Loading @@ -415,6 +405,17 @@ static CURLcode bindlocal(struct connectdata *conn, socksize = sizeof(struct sockaddr); } #ifdef ENABLE_IPV6 else { /* AF_INET6 */ memset(&me6, 0, sizeof(struct sockaddr)); me6.sin6_family = AF_INET6; me6.sin6_addr = in6addr_any; sock = (struct sockaddr *)&me6; socksize = sizeof(struct sockaddr); } #endif } else /* no local kind of binding was requested */ return CURLE_OK; Loading @@ -432,11 +433,11 @@ static CURLcode bindlocal(struct connectdata *conn, if( bind(sockfd, sock, socksize) >= 0) { /* we succeeded to bind */ struct Curl_sockaddr_storage add; socklen_t size; size = sizeof(add); socklen_t size = sizeof(add); if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { failf(data, "getsockname() failed"); if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } /* We re-use/clobber the port variable here below */ Loading @@ -448,6 +449,8 @@ static CURLcode bindlocal(struct connectdata *conn, #endif infof(data, "Local port: %d\n", port); conn->bits.bound = TRUE; if(h) Curl_resolv_unlock(data, h); return CURLE_OK; } if(--portnum > 0) { Loading @@ -461,8 +464,10 @@ static CURLcode bindlocal(struct connectdata *conn, data->state.os_errno = SOCKERRNO; failf(data, "bind failure: %s", Curl_strerror(conn, data->state.os_errno)); return CURLE_INTERFACE_FAILED; if(h) Curl_resolv_unlock(data, h); return CURLE_INTERFACE_FAILED; } /* Loading Loading @@ -822,7 +827,7 @@ singleipconnect(struct connectdata *conn, } /* possibly bind the local end to an IP, interface or port */ res = bindlocal(conn, sockfd); res = bindlocal(conn, sockfd, addr->family); if(res) { sclose(sockfd); /* close socket and bail out */ return CURL_SOCKET_BAD; Loading
lib/ftp.c +6 −6 Original line number Diff line number Diff line Loading @@ -892,7 +892,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(data->set.str[STRING_FTPPORT] && (strlen(data->set.str[STRING_FTPPORT]) > 1)) { /* attempt to get the address of the given interface name */ if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) if(!Curl_if2ip(conn->ip_addr->ai_family, data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) /* not an interface, use the given string as host name instead */ host = data->set.str[STRING_FTPPORT]; else Loading Loading @@ -964,8 +965,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* It failed. Bind the address used for the control connection instead */ sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)sa, &sslen)) { if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); sclose(portsock); Loading @@ -973,7 +973,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, } /* set port number to zero to make bind() pick "any" */ if(((struct sockaddr *)sa)->sa_family == AF_INET) if(sa->sa_family == AF_INET) ((struct sockaddr_in *)sa)->sin_port=0; else ((struct sockaddr_in6 *)sa)->sin6_port =0; Loading @@ -981,7 +981,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(sslen > (socklen_t)sizeof(ss)) sslen = sizeof(ss); if(bind(portsock, (struct sockaddr *)sa, sslen)) { if(bind(portsock, sa, sslen)) { failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO)); sclose(portsock); return CURLE_FTP_PORT_FAILED; Loading Loading @@ -1112,7 +1112,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* this is an IPv4 address */ addr = Curl_ip2addr(in, ftpportstr, 0); else { if(Curl_if2ip(ftpportstr, myhost, sizeof(myhost))) { if(Curl_if2ip(AF_INET, ftpportstr, myhost, sizeof(myhost))) { /* The interface to IP conversion provided a dotted address */ in=inet_addr(myhost); addr = Curl_ip2addr(in, myhost, 0); Loading