You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2009/05/27 23:42:01 UTC

svn commit: r779323 - /httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c

Author: wrowe
Date: Wed May 27 21:42:01 2009
New Revision: 779323

URL: http://svn.apache.org/viewvc?rev=779323&view=rev
Log:
Some preparation - merging server-side sockaddr handling for PORT/EPRT
to prepare to handle PORT/EPRT connections from low numbered ports 

Modified:
    httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c

Modified: httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c?rev=779323&r1=779322&r2=779323&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c (original)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c Wed May 27 21:42:01 2009
@@ -1716,53 +1716,67 @@
     return FTP_REPLY_COMMAND_OK;
 }
 
-
-static int ftp_cmd_eprt(request_rec *r, const char *arg)
+static int get_outbound_port(apr_sockaddr_t **sa_rv, request_rec *r,
+                             apr_int32_t family)
 {
-    ftp_server_config *fsc = ftp_get_module_config(r->server->module_config);
-    ftp_connection *fc = ftp_get_module_config(r->connection->conn_config);
     conn_rec *c = r->connection;
+    ftp_connection *fc = ftp_get_module_config(c->conn_config);
+    ftp_server_config *fsc = ftp_get_module_config(r->server->module_config);
     apr_sockaddr_t *sa;
     apr_socket_t *s;
     apr_status_t rv;
-    char *arg_tok, *ip_addr;
-    apr_int32_t family;
-    apr_port_t port;
-    int res;
-
-    ftp_reset_dataconn(fc);
+    apr_port_t local_port;
 
-    if (fc->all_epsv) {
-        fc->response_notes = apr_pstrdup(r->pool, "Restricted by EPSV ALL ");
-        return FTP_REPLY_BAD_SEQUENCE;
+    if (fsc->active_min == -1) {
+        local_port = 0;
     }
-
-    arg_tok = apr_pstrdup(fc->data_pool, arg);
-    if ((res = ftp_eprt_decode(&family, &ip_addr, &port, arg_tok))
-        != FTP_REPLY_COMMAND_OK) {
-        fc->response_notes = apr_pstrdup(r->pool, "Invalid EPRT request");
-        return res;
+    else if (fsc->active_max == fsc->active_min) {
+        local_port = fsc->active_min;
+    }
+    else {
+        local_port = fsc->active_min +
+            (apr_port_t) (rand() % (fsc->active_max -
+                                    fsc->active_min + 1));
     }
 
-    sa = apr_palloc(fc->data_pool, sizeof(apr_sockaddr_t));
-    memcpy(sa, c->local_addr, sizeof(apr_sockaddr_t));
-    sa->next = NULL;
-    if (sa->family == APR_INET)
-        sa->ipaddr_ptr = &(sa->sa.sin.sin_addr);
+    if (c->local_addr->family == family) {
+        /* Shortcut; duplicate the contents */
+        sa = apr_palloc(fc->data_pool, sizeof(apr_sockaddr_t));
+        memcpy(sa, c->local_addr, sizeof(apr_sockaddr_t));
+        sa->next = NULL;
+        if (sa->family == APR_INET)
+            sa->ipaddr_ptr = &(sa->sa.sin.sin_addr);
 #if APR_HAVE_IPV6
-    else if (sa->family == APR_INET6)
-        sa->ipaddr_ptr = &(sa->sa.sin6.sin6_addr);
+        else if (sa->family == APR_INET6)
+            sa->ipaddr_ptr = &(sa->sa.sin6.sin6_addr);
 #endif
-
-    if (fsc->active_min != -1) {
-        sa->port = fsc->active_min +
-            (apr_port_t) (rand() % (fsc->active_max -
-                                    fsc->active_min + 1));
+        sa->sa.sin.sin_port = htons(local_port);
     }
     else {
-        sa->port = 0;
+        /* Long way around, create a fresh sa, attempt to use 
+         * the original port, before falling back on the nul adapter
+         * TODO: this could use a config option to specify the
+         * preferred interface/local address
+         */
+        rv = apr_sockaddr_info_get(&sa, c->local_ip, family,
+                                   local_port, 0, fc->data_pool);
+        if (!sa || rv) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
+                          "Couldn't resolve explicit local socket address"
+                          " %s (apr or socket stack bug?)  Retrying",
+                          c->local_ip);
+            rv = apr_sockaddr_info_get(&sa, NULL, APR_INET,
+                                       local_port, 0, fc->data_pool);
+        }
+
+        if (!sa || rv) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                          "Couldn't resolve emphemeral local socket address"
+                          " (apr or socket stack bug?)  Giving up");
+            apr_socket_close(s);
+            return FTP_REPLY_CANNOT_OPEN_DATACONN;
+        }
     }
-    sa->sa.sin.sin_port = htons(sa->port);
 
 #if APR_MAJOR_VERSION < 1
     rv = apr_socket_create_ex(&s, family, SOCK_STREAM, APR_PROTO_TCP,
@@ -1790,9 +1804,9 @@
          * worker processes.
          */
     }
+    else
 #endif
-
-    rv = apr_socket_bind(s, sa);
+        rv = apr_socket_bind(s, sa);
 
     if (rv != APR_SUCCESS) {
 #ifdef EACCES
@@ -1807,6 +1821,38 @@
         return FTP_REPLY_CANNOT_OPEN_DATACONN;
     }
 
+    *sa_rv = sa;
+    fc->csock = s;
+    fc->response_notes = apr_psprintf(r->pool, FTP_MSG_SUCCESS, r->method);
+    return FTP_REPLY_COMMAND_OK;
+}
+
+static int ftp_cmd_eprt(request_rec *r, const char *arg)
+{
+    conn_rec *c = r->connection;
+    ftp_connection *fc = ftp_get_module_config(c->conn_config);
+    ftp_server_config *fsc = ftp_get_module_config(r->server->module_config);
+    apr_sockaddr_t *sa;
+    apr_status_t rv;
+    char *arg_tok, *ip_addr;
+    apr_int32_t family;
+    apr_port_t port;
+    int res;
+
+    ftp_reset_dataconn(fc);
+
+    if (fc->all_epsv) {
+        fc->response_notes = apr_pstrdup(r->pool, "Restricted by EPSV ALL ");
+        return FTP_REPLY_BAD_SEQUENCE;
+    }
+
+    arg_tok = apr_pstrdup(fc->data_pool, arg);
+    if ((res = ftp_eprt_decode(&family, &ip_addr, &port, arg_tok))
+        != FTP_REPLY_COMMAND_OK) {
+        fc->response_notes = apr_pstrdup(r->pool, "Invalid EPRT request");
+        return res;
+    }
+
     rv = apr_sockaddr_info_get(&fc->clientsa, ip_addr, family,
                                port, 0, fc->data_pool);
     if (!fc->clientsa || rv) {
@@ -1819,7 +1865,6 @@
 #endif
         fc->response_notes = apr_pstrdup(r->pool,
                          "Invalid EPRT command, unable to resolve request");
-        apr_socket_close(s);
         return FTP_REPLY_SYNTAX_ERROR;
     }
 
@@ -1844,25 +1889,20 @@
                          test_ip, c->remote_ip);
             fc->response_notes = apr_pstrdup(r->pool,
                        "Invalid EPRT command, proxy EPRT is not permitted");
-            apr_socket_close(s);
             return FTP_REPLY_SYNTAX_ERROR;
         }
     }
 
-    fc->response_notes = apr_psprintf(r->pool, FTP_MSG_SUCCESS, r->method);
-    fc->csock = s;
-    return FTP_REPLY_COMMAND_OK;
+    return get_outbound_port(&sa, r, family);
 }
 
 static int ftp_cmd_port(request_rec *r, const char *arg)
 {
-    ftp_server_config *fsc = ftp_get_module_config(r->server->module_config);
-    ftp_connection *fc = ftp_get_module_config(r->connection->conn_config);
     conn_rec *c = r->connection;
+    ftp_connection *fc = ftp_get_module_config(c->conn_config);
+    ftp_server_config *fsc = ftp_get_module_config(r->server->module_config);
     apr_sockaddr_t *sa;
-    apr_socket_t *s;
     apr_status_t rv;
-    apr_port_t local_port;
     apr_port_t port;
     char *ip_addr, tc;
     int res, val[6];
@@ -1905,84 +1945,6 @@
         }
     }
 
-    if (fsc->active_min != -1) {
-        local_port = fsc->active_min +
-            (apr_port_t) (rand() % (fsc->active_max -
-                                    fsc->active_min + 1));
-    }
-    else {
-        local_port = 0;
-    }
-
-    if (c->local_addr->family == APR_INET) {
-        rv = apr_sockaddr_info_get(&sa, c->local_ip, APR_INET,
-                                   local_port, 0, fc->data_pool);
-        if (!sa || rv) {
-            ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
-                          "Couldn't resolve explicit local socket address"
-                          " %s (apr or socket stack bug?)  Retrying",
-                          c->local_ip);
-            rv = apr_sockaddr_info_get(&sa, NULL, APR_INET,
-                                       local_port, 0, fc->data_pool);
-        }
-    }
-    else {
-        rv = apr_sockaddr_info_get(&sa, NULL, APR_INET,
-                                   local_port, 0, fc->data_pool);
-    }
-
-    if (!sa || rv) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                      "Couldn't resolve emphemeral local socket address"
-                      " (apr or socket stack bug?)  Giving up");
-        apr_socket_close(s);
-        return FTP_REPLY_CANNOT_OPEN_DATACONN;
-    }
-
-#if APR_MAJOR_VERSION < 1
-    rv = apr_socket_create_ex(&s, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
-                              fc->data_pool);
-#else
-    rv = apr_socket_create(&s, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
-                           fc->data_pool);
-#endif
-
-    if (rv != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
-                     "Couldn't create socket");
-        return FTP_REPLY_CANNOT_OPEN_DATACONN;
-    }
-
-    apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);
-
-#if 0
-    if ((fsc->active_min != -1) && (fsc->active_min < 1024)) {
-        /*
-         * Here's the case of low numbered port creation; the only way to
-         * accomplish this is either grant the apache user/group the right to
-         * bind to low numbered ports, or to have the parent running as root
-         * spin off socket fd's through a domain socket to all interested ftp
-         * worker processes.
-         */
-    }
-    else
-#endif
-
-    rv = apr_socket_bind(s, sa);
-
-    if (rv != APR_SUCCESS) {
-#ifdef EACCES
-        if (sa->port < 1024 && rv == EACCES)
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                          "Couldn't bind to low numbered port (<1024)");
-        else
-#endif
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
-                         "Couldn't bind to socket");
-        apr_socket_close(s);
-        return FTP_REPLY_CANNOT_OPEN_DATACONN;
-    }
-
     rv = apr_sockaddr_info_get(&fc->clientsa, ip_addr, APR_INET,
                                port, 0, fc->data_pool);
 
@@ -1990,13 +1952,10 @@
         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                       "Couldn't resolve remote socket address %s"
                       " (apr or socket stack bug?)", ip_addr);
-        apr_socket_close(s);
         return FTP_REPLY_CANNOT_OPEN_DATACONN;
     }
 
-    fc->response_notes = apr_psprintf(r->pool, FTP_MSG_SUCCESS, r->method);
-    fc->csock = s;
-    return FTP_REPLY_COMMAND_OK;
+    return get_outbound_port(&sa, r, APR_INET);
 }
 
 static int ftp_cmd_prot(request_rec *r, const char *arg)