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



Reply via email to