Colm MacCarthaigh wrote:
On Mon, Dec 10, 2007 at 12:57:18PM -0600, William A. Rowe, Jr. wrote:
Now apr has provided a tuple of ip address, family and port that
cannot be reconstituted by APR. So, for example, where we have
to create a connection to the very same host/family on a different
port, it becomes impossible.
O.k., so the scenario is ;
1. Host application listens on :: , accepts incoming socket
from ::ffff:127.0.0.1
2. Host application resolves the IP into a text format.
(calls getnameinfo or whatever)
3. Host application takes that text format and turns
it back into a sockaddr. (calls getaddrinfo or whatever)
4. Connects to that IP.
Why would it ever do steps 2 and 3?
Maybe we should support using INET6 sockets for outbound IPv4
connections more - and the patch would enable that for connections
involving lookups - but the use-case scanario is mighty strange, it has
to go through a text lookup.
They know the family and IP from an existing connection, and that
existing connection is internally inconsistent.
How? we don't modify the sockaddr.
See this file;
http://svn.apache.org/repos/asf/httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c
Jump into the ftp_cmd_eprt function...
/* XXX: Anything special to handle IPv6 ip_addr string where c->remote_ip
* is IPv4 mapped?
*/
if (((c->local_addr->family == APR_INET) && (family == APR_INET))
#if APR_HAVE_IPV6
|| ((c->local_addr->family == APR_INET6) && (family == APR_INET6))
#endif
) {
apr_sockaddr_info_get(&sa, c->local_ip, family,
local_port, 0, c->pool);
if (!sa) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"Couldn't resolve explicit local socket address"
" (apr or socket stack bug?) Retrying");
apr_sockaddr_info_get(&sa, NULL, family,
local_port, 0, c->pool);
}
}
else {
/* If the family differs, it's difficult to map the EPRT origin IP */
apr_sockaddr_info_get(&sa, NULL, family,
local_port, 0, c->pool);
}
if (!sa) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
"Couldn't resolve local socket address"
" (apr or socket stack bug?) Giving up");
return FTP_REPLY_CANNOT_OPEN_DATACONN;
}
apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);
rv = apr_socket_bind(s, sa);
To decipher; FTP by design should originate the connection to the client's
specified adapter from the *same adapter/address* to which the client had
connected.
In httpd, we know this from the c->local_addr.
Here, we take the c->local_ip and c->family, but we now need to give this
a different outgoing port assignment. We reconstruct a sockaddr_t that
consists of the IP, Family, and our new idea for a origin port.
This code in apr-1.2 falls through to the (!sa) case because 127.0.0.1
and family APR_INET6 returns NULL for the sa. then (as Joe hinted) we
can always retry with UNSPEC. But that means we do route through a
different interface, potentially.
This code with apr-1.x succeeds to bind to 127.0.0.1 as an IPV6 mapped
IPV6 address, so the interface is preserved.
Now; are you suggesting that it would be more efficient and effective
if we cloned the local_addr structure, modified the port and directly
used the clone to apr_socket_bind rather than going through these extra
apr_sockaddr_info_get gymnastics?
If so, what is the proper method to clone an sa in the apr schema?
Bill