From: Christos Tsantilas Date: Fri, 4 Apr 2014 16:36:47 +0000 (+0300) Subject: ftp_epsv ACLs X-Git-Tag: SQUID_3_5_0_1~304 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ddf5aa2bbc5550e64e9cbd5b5814a0f4eba41882;p=thirdparty%2Fsquid.git ftp_epsv ACLs This patch add support for ftp_epsv ACLs. The following syntax is supported: ftp_epsv on ftp_epsv off ftp_epsv deny acl1 ftp_epsv allow acl2 acl3 The action of the first matching line wins. The "ftp_epsv on|off" syntax is supported for backward compatibility. This is a Measurement Factory project --- diff --git a/src/SquidConfig.h b/src/SquidConfig.h index 9c336f198b..97d09a3100 100644 --- a/src/SquidConfig.h +++ b/src/SquidConfig.h @@ -398,6 +398,8 @@ public: /// spoof_client_ip squid.conf acl. /// nil unless configured acl_access* spoof_client_ip; + + acl_access *ftp_epsv; } accessList; AclDenyInfoList *denyInfoList; diff --git a/src/cache_cf.cc b/src/cache_cf.cc index db08f99061..9774fb6c9c 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -243,6 +243,10 @@ static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_acce static void free_sslproxy_ssl_bump(acl_access **ssl_bump); #endif /* USE_OPENSSL */ +static void parse_ftp_epsv(acl_access **ftp_epsv); +static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv); +static void free_ftp_epsv(acl_access **ftp_epsv); + static void parse_b_size_t(size_t * var); static void parse_b_int64_t(int64_t * var); @@ -4819,6 +4823,76 @@ static void free_note(Notes *notes) notes->clean(); } +static bool FtpEspvDeprecated = false; +static void parse_ftp_epsv(acl_access **ftp_epsv) +{ + allow_t ftpEpsvDeprecatedAction; + bool ftpEpsvIsDeprecatedRule = false; + + char *t = ConfigParser::PeekAtToken(); + if (!t){ + self_destruct(); + return; + } + + if (!strcmp(t, "off")) { + (void)ConfigParser::NextToken(); + ftpEpsvIsDeprecatedRule = true; + ftpEpsvDeprecatedAction = allow_t(ACCESS_DENIED); + } else if (!strcmp(t, "on")) { + (void)ConfigParser::NextToken(); + ftpEpsvIsDeprecatedRule = true; + ftpEpsvDeprecatedAction = allow_t(ACCESS_ALLOWED); + } + + // Check for mixing "ftp_epsv on|off" and "ftp_epsv allow|deny .." rules: + // 1) if this line is "ftp_epsv allow|deny ..." and already exist rules of "ftp_epsv on|off" + // 2) if this line is "ftp_epsv on|off" and already exist rules of "ftp_epsv allow|deny ..." + // then abort + if ((!ftpEpsvIsDeprecatedRule && FtpEspvDeprecated) || + (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != NULL)) { + debugs(3, DBG_CRITICAL, "FATAL: do not mix \"ftp_epsv on|off\" cfg lines with \"ftp_epsv allow|deny ...\" cfg lines. Update your ftp_epsv rules."); + self_destruct(); + } + + if (ftpEpsvIsDeprecatedRule) { + // overwrite previous ftp_epsv lines + delete *ftp_epsv; + if (ftpEpsvDeprecatedAction == allow_t(ACCESS_DENIED)) { + Acl::AndNode *ftpEpsvRule = new Acl::AndNode; + ftpEpsvRule->context("(ftp_epsv rule)", config_input_line); + ACL *a = ACL::FindByName("all"); + if (!a) { + self_destruct(); + return; + } + ftpEpsvRule->add(a); + *ftp_epsv = new Acl::Tree; + (*ftp_epsv)->context("(ftp_epsv rules)", config_input_line); + (*ftp_epsv)->add(ftpEpsvRule, ftpEpsvDeprecatedAction); + } else + *ftp_epsv = NULL; + FtpEspvDeprecated = true; + } else { + aclParseAccessLine(cfg_directive, LegacyParser, ftp_epsv); + } +} + +static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv) +{ + if (ftp_epsv) { + wordlist *lines = ftp_epsv->treeDump(name, NULL); + dump_wordlist(entry, lines); + wordlistDestroy(&lines); + } +} + +static void free_ftp_epsv(acl_access **ftp_epsv) +{ + free_acl_access(ftp_epsv); + FtpEspvDeprecated = false; +} + static void parse_configuration_includes_quoted_values(bool *recognizeQuotedValues) { diff --git a/src/cf.data.depend b/src/cf.data.depend index cfd5400c87..4776fd6bad 100644 --- a/src/cf.data.depend +++ b/src/cf.data.depend @@ -75,3 +75,4 @@ wordlist sslproxy_ssl_bump acl sslproxy_cert_sign acl sslproxy_cert_adapt acl +ftp_epsv acl diff --git a/src/cf.data.pre b/src/cf.data.pre index b3ef746467..bde3b51bbe 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -4486,9 +4486,9 @@ DOC_START DOC_END NAME: ftp_epsv -TYPE: onoff -DEFAULT: on -LOC: Config.Ftp.epsv +TYPE: ftp_epsv +DEFAULT: none +LOC: Config.accessList.ftp_epsv DOC_START FTP Protocol extensions permit the use of a special "EPSV" command. @@ -4497,10 +4497,18 @@ DOC_START and therefore, translation of the data portion of the segments will never be needed. - Turning this OFF will prevent EPSV being attempted. - WARNING: Doing so will convert Squid back to the old behavior with all - the related problems with external NAT devices/layers. + EPSV is often required to interoperate with FTP servers on IPv6 + networks. On the other hand, it may break some IPv4 servers. + + By default, EPSV may try EPSV with any FTP server. To fine tune + that decision, you may restrict EPSV to certain clients or servers + using ACLs: + + ftp_epsv allow|deny al1 acl2 ... + + WARNING: Disabling EPSV may cause problems with external NAT and IPv6. + Only fast ACLs are supported. Requires ftp_passive to be ON (default) for any effect. DOC_END diff --git a/src/ftp.cc b/src/ftp.cc index 9f1fd39e3a..10f96a1ad9 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -31,6 +31,7 @@ */ #include "squid.h" +#include "acl/FilledChecklist.h" #include "comm.h" #include "comm/ConnOpener.h" #include "comm/TcpAcceptor.h" @@ -2560,8 +2561,13 @@ ftpSendPassive(FtpStateData * ftpState) ftpState->state = SENT_PASV; break; - default: - if (!Config.Ftp.epsv) { + default: { + bool doEpsv = true; + if (Config.accessList.ftp_epsv) { + ACLFilledChecklist checklist(Config.accessList.ftp_epsv, ftpState->fwd->request, NULL); + doEpsv = (checklist.fastCheck() == ACCESS_ALLOWED); + } + if (!doEpsv) { debugs(9, 5, HERE << "EPSV support manually disabled. Sending PASV for FTP Channel (" << ftpState->ctrl.conn->remote <<")"); snprintf(cbuf, CTRL_BUFLEN, "PASV\r\n"); ftpState->state = SENT_PASV; @@ -2583,6 +2589,7 @@ ftpSendPassive(FtpStateData * ftpState) ftpState->state = SENT_EPSV_1; } } + } break; }