]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
ftp_epsv ACLs
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Fri, 4 Apr 2014 16:36:47 +0000 (19:36 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Fri, 4 Apr 2014 16:36:47 +0000 (19:36 +0300)
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

src/SquidConfig.h
src/cache_cf.cc
src/cf.data.depend
src/cf.data.pre
src/ftp.cc

index 9c336f198b9e32e7a43f79711e95b331997029e3..97d09a31002ec3c081b6d5fd44b91ef2403f8a24 100644 (file)
@@ -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;
 
index db08f99061419b33f3545b3bf07abaa964f2b425..9774fb6c9c2e0d11156167732713e1eba87a2b02 100644 (file)
@@ -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)
 {
index cfd5400c871a2228fcfff851d7341a4f5facddab..4776fd6bade899cdc561c55f7a07f8c8bb3b4eaf 100644 (file)
@@ -75,3 +75,4 @@ wordlist
 sslproxy_ssl_bump      acl
 sslproxy_cert_sign     acl
 sslproxy_cert_adapt    acl
+ftp_epsv                acl
index b3ef7464671cc0f14957533219d64c367cba881a..bde3b51bbe8a080e7efc27af4618725e864f8933 100644 (file)
@@ -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
 
index 9f1fd39e3a6fdd829bc6b9cf225770977fe0ae25..10f96a1ad95c1ecf948590f8ad7f9e1a9a931d44 100644 (file)
@@ -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;
     }