⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_proxy_ftp.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 5 页
字号:
        /*         * RFC2616 states: 14.37 Retry-After         *         * The Retry-After response-header field can be used with a 503 (Service         * Unavailable) response to indicate how long the service is expected         * to be unavailable to the requesting client. [...] The value of         * this field can be either an HTTP-date or an integer number of         * seconds (in decimal) after the time of the response. Retry-After         * = "Retry-After" ":" ( HTTP-date | delta-seconds )         */        char *secs_str = ftpmessage;        time_t secs;        /* Look for a number, preceded by whitespace */        while (*secs_str)            if ((secs_str==ftpmessage || apr_isspace(secs_str[-1])) &&                apr_isdigit(secs_str[0]))                break;        if (*secs_str != '\0') {            secs = atol(secs_str);            apr_table_add(r->headers_out, "Retry-After",                          apr_psprintf(p, "%lu", (unsigned long)(60 * secs)));        }        return ftp_proxyerror(r, backend, HTTP_SERVICE_UNAVAILABLE, ftpmessage);    }    if (rc != 220) {        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);    }    rc = proxy_ftp_command(apr_pstrcat(p, "USER ", user, CRLF, NULL),                           r, origin, bb, &ftpmessage);    /* possible results; 230, 331, 332, 421, 500, 501, 530 */    /* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */    /* 230 User logged in, proceed. */    /* 331 User name okay, need password. */    /* 332 Need account for login. */    /* 421 Service not available, closing control connection. */    /* 500 Syntax error, command unrecognized. */    /* (This may include errors such as command line too long.) */    /* 501 Syntax error in parameters or arguments. */    /* 530 Not logged in. */    if (rc == -1 || rc == 421) {        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, "Error reading from remote server");    }    if (rc == 530) {        proxy_ftp_cleanup(r, backend);        return ftp_unauthorized(r, 1);  /* log it: user name guessing                                         * attempt? */    }    if (rc != 230 && rc != 331) {        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);    }    if (rc == 331) {            /* send password */        if (password == NULL) {            proxy_ftp_cleanup(r, backend);            return ftp_unauthorized(r, 0);        }        rc = proxy_ftp_command(apr_pstrcat(p, "PASS ", password, CRLF, NULL),                           r, origin, bb, &ftpmessage);        /* possible results 202, 230, 332, 421, 500, 501, 503, 530 */        /* 230 User logged in, proceed. */        /* 332 Need account for login. */        /* 421 Service not available, closing control connection. */        /* 500 Syntax error, command unrecognized. */        /* 501 Syntax error in parameters or arguments. */        /* 503 Bad sequence of commands. */        /* 530 Not logged in. */        if (rc == -1 || rc == 421) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,                                  "Error reading from remote server");        }        if (rc == 332) {            return ftp_proxyerror(r, backend, HTTP_UNAUTHORIZED,                  apr_pstrcat(p, "Need account for login: ", ftpmessage, NULL));        }        /* @@@ questionable -- we might as well return a 403 Forbidden here */        if (rc == 530) {            proxy_ftp_cleanup(r, backend);            return ftp_unauthorized(r, 1);      /* log it: passwd guessing                                                 * attempt? */        }        if (rc != 230 && rc != 202) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);        }    }    apr_table_set(r->notes, "Directory-README", ftpmessage);    /* Special handling for leading "%2f": this enforces a "cwd /"     * out of the $HOME directory which was the starting point after login     */    if (strncasecmp(path, "%2f", 3) == 0) {        path += 3;        while (*path == '/') /* skip leading '/' (after root %2f) */            ++path;        rc = proxy_ftp_command("CWD /" CRLF, r, origin, bb, &ftpmessage);        if (rc == -1 || rc == 421)            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,                                  "Error reading from remote server");    }    /*     * set the directory (walk directory component by component): this is     * what we must do if we don't know the OS type of the remote machine     */    for (;;) {        strp = strchr(path, '/');        if (strp == NULL)            break;        *strp = '\0';        len = decodeenc(path); /* Note! This decodes a %2f -> "/" */        if (strchr(path, '/')) { /* are there now any '/' characters? */            return ftp_proxyerror(r, backend, HTTP_BAD_REQUEST,                                  "Use of /%2f is only allowed at the base directory");        }        /* NOTE: FTP servers do globbing on the path.         * So we need to escape the URI metacharacters.         * We use a special glob-escaping routine to escape globbing chars.         * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH         */        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",                           ftp_escape_globbingchars(p, path), CRLF, NULL),                           r, origin, bb, &ftpmessage);        *strp = '/';        /* responses: 250, 421, 500, 501, 502, 530, 550 */        /* 250 Requested file action okay, completed. */        /* 421 Service not available, closing control connection. */        /* 500 Syntax error, command unrecognized. */        /* 501 Syntax error in parameters or arguments. */        /* 502 Command not implemented. */        /* 530 Not logged in. */        /* 550 Requested action not taken. */        if (rc == -1 || rc == 421) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,                                  "Error reading from remote server");        }        if (rc == 550) {            return ftp_proxyerror(r, backend, HTTP_NOT_FOUND, ftpmessage);        }        if (rc != 250) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);        }        path = strp + 1;    }    /*     * IV: Make Data Connection? -------------------------     *     * Try EPSV, if that fails... try PASV, if that fails... try PORT.     *//* this temporarily switches off EPSV/PASV *//*goto bypass;*/    /* set up data connection - EPSV */    {        apr_sockaddr_t *data_addr;        char *data_ip;        apr_port_t data_port;        /*         * The EPSV command replaces PASV where both IPV4 and IPV6 is         * supported. Only the port is returned, the IP address is always the         * same as that on the control connection. Example: Entering Extended         * Passive Mode (|||6446|)         */        rc = proxy_ftp_command("EPSV" CRLF,                           r, origin, bb, &ftpmessage);        /* possible results: 227, 421, 500, 501, 502, 530 */        /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */        /* 421 Service not available, closing control connection. */        /* 500 Syntax error, command unrecognized. */        /* 501 Syntax error in parameters or arguments. */        /* 502 Command not implemented. */        /* 530 Not logged in. */        if (rc == -1 || rc == 421) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,                                  "Error reading from remote server");        }        if (rc != 229 && rc != 500 && rc != 501 && rc != 502) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);        }        else if (rc == 229) {            char *pstr;            char *tok_cntx;            pstr = ftpmessage;            pstr = apr_strtok(pstr, " ", &tok_cntx);    /* separate result code */            if (pstr != NULL) {                if (*(pstr + strlen(pstr) + 1) == '=') {                    pstr += strlen(pstr) + 2;                }                else {                    pstr = apr_strtok(NULL, "(", &tok_cntx);    /* separate address &                                                                 * port params */                    if (pstr != NULL)                        pstr = apr_strtok(NULL, ")", &tok_cntx);                }            }            if (pstr) {                apr_sockaddr_t *epsv_addr;                data_port = atoi(pstr + 3);                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                       "proxy: FTP: EPSV contacting remote host on port %d",                             data_port);                if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                  "proxy: FTP: error creating EPSV socket");                    proxy_ftp_cleanup(r, backend);                    return HTTP_INTERNAL_SERVER_ERROR;                }#if !defined (TPF) && !defined(BEOS)                if (conf->recv_buffer_size > 0                        && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,                                                    conf->recv_buffer_size))) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                  "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");                }#endif                rv = apr_socket_opt_set(data_sock, APR_TCP_NODELAY, 1);                if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                 "apr_socket_opt_set(APR_TCP_NODELAY): Failed to set");                }                /* make the connection */                apr_socket_addr_get(&data_addr, APR_REMOTE, sock);                apr_sockaddr_ip_get(&data_ip, data_addr);                apr_sockaddr_info_get(&epsv_addr, data_ip, connect_addr->family, data_port, 0, p);                rv = apr_socket_connect(data_sock, epsv_addr);                if (rv != APR_SUCCESS) {                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,                                 "proxy: FTP: EPSV attempt to connect to %pI failed - Firewall/NAT?", epsv_addr);                    return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,                                                                           "EPSV attempt to connect to %pI failed - firewall/NAT?", epsv_addr));                }                else {                    connect = 1;                }            }            else {                /* and try the regular way */                apr_socket_close(data_sock);            }        }    }    /* set up data connection - PASV */    if (!connect) {        rc = proxy_ftp_command("PASV" CRLF,                           r, origin, bb, &ftpmessage);        /* possible results: 227, 421, 500, 501, 502, 530 */        /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */        /* 421 Service not available, closing control connection. */        /* 500 Syntax error, command unrecognized. */        /* 501 Syntax error in parameters or arguments. */        /* 502 Command not implemented. */        /* 530 Not logged in. */        if (rc == -1 || rc == 421) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,                                  "Error reading from remote server");        }        if (rc != 227 && rc != 502) {            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);        }        else if (rc == 227) {            unsigned int h0, h1, h2, h3, p0, p1;            char *pstr;            char *tok_cntx;/* FIXME: Check PASV against RFC1123 */            pstr = ftpmessage;            pstr = apr_strtok(pstr, " ", &tok_cntx);    /* separate result code */            if (pstr != NULL) {                if (*(pstr + strlen(pstr) + 1) == '=') {                    pstr += strlen(pstr) + 2;                }                else {                    pstr = apr_strtok(NULL, "(", &tok_cntx);    /* separate address &                                                                 * port params */                    if (pstr != NULL)                        pstr = apr_strtok(NULL, ")", &tok_cntx);                }            }/* FIXME: Only supports IPV4 - fix in RFC2428 */            if (pstr != NULL && (sscanf(pstr,                 "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {                apr_sockaddr_t *pasv_addr;                apr_port_t pasvport = (p1 << 8) + p0;                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                          "proxy: FTP: PASV contacting host %d.%d.%d.%d:%d",                             h3, h2, h1, h0, pasvport);                if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                  "proxy: error creating PASV socket");                    proxy_ftp_cleanup(r, backend);                    return HTTP_INTERNAL_SERVER_ERROR;                }#if !defined (TPF) && !defined(BEOS)                if (conf->recv_buffer_size > 0                        && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,                                                    conf->recv_buffer_size))) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                  "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");                }#endif                rv = apr_socket_opt_set(data_sock, APR_TCP_NODELAY, 1);                if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                                 "apr_socket_opt_set(APR_TCP_NODELAY): Failed to set");                }                /* make the connection */                apr_sockaddr_info_get(&pasv_addr, apr_psprintf(p, "%d.%d.%d.%d", h3, h2, h1, h0), connect_addr->family, pasvport, 0, p);                rv = apr_socket_connect(data_sock, pasv_addr);                if (rv != APR_SUCCESS) {                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,                                 "proxy: FTP: PASV attempt to connect to %pI failed - Firewall/NAT?", pasv_addr);                    return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,                                                                           "PASV attempt to connect to %pI failed - firewall/NAT?", pasv_addr));                }                else {                    connect = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -