让 pure-ftpd 的 -P (forcepassiveip) 参数,只用在远端连接

pureftpd 如果配置了远端 -p (--passiveportrange) 模式后,在内网连接时无法连接的问题,可以通过修改以下代码重新编译解决问题 创建 /etc/localnet 文件,该文件格式为 AAA.BBB.CCC.DDD/WWW...

pureftpd 如果配置了远端 -p (--passiveportrange) 模式后,在内网连接时无法连接的问题,可以通过修改以下代码重新编译解决问题。

创建 /etc/localnet 文件,该文件格式为:

AAA.BBB.CCC.DDD/WWW.XXX.YYY.ZZZ 如: 192.168.0.0/255.255.0.0

diff -Nur src.orig/ftpd.c src.patch/ftpd.c
--- src.orig/ftpd.c 2006-06-12 18:44:25.000000000 +0800
+++ src.patch/ftpd.c    2006-06-12 22:52:37.590994047 +0800
@@ -405,6 +405,48 @@
     (void) title;
 }
 
+// add by twu2 20060612 begin
+// check local net in /etc/localnet
+static void check_local_net(const struct sockaddr_storage * const addr)
+{
+    FILE *fp;
+    unsigned long a1 = 0U;
+    unsigned long a2 = 0U;
+    unsigned long mask = 0U;
+    unsigned int b1, b2, b3, b4;
+    unsigned int m1, m2, m3, m4;
+    char buf[1024];
+
+    if (addr == NULL) return;
+    // only for IPV4 now
+    if (STORAGE_FAMILY(*addr) != AF_INET) return;
+    a1 = ntohl(STORAGE_SIN_ADDR(*addr));
+    fp = fopen("/etc/localnet", "rt");
+    // no localnet file
+    if (fp == NULL) return;
+    while (1) {
+        if (fgets(buf, 1024, fp) == NULL) break;
+        b1 = b2 = b3 = b4 = m1 = m2 = m3 = m4 = 0;
+        if ((sscanf(buf, "%u.%u.%u.%u/%u.%u.%u.%u", &b1, &b2, &b3, &b4, &m1, &m2, &m3, &m4) != 8) ||
+            b1 > 255U || b2 > 255U || b3 > 255U || b4 > 255U ||
+            (b1 | b2 | b3 | b4) == 0U ||
+            m1 > 255U || m2 > 255U || m3 > 255U || m4 > 255U ||
+            (m1 | m2 | m3 | m4) == 0U)
+            continue;
+        a2 = b1 << 24 | b2 << 16 | b3 << 8 | b4;
+        mask = m1 << 24 | m2 << 16 | m3 << 8 | m4;
+        // correct format
+        if ((a1 & mask) == (a2 & mask)) {
+            // same subnet
+            is_local = 1;
+            break;
+        }
+    }
+    fclose(fp);
+    return;
+}
+// add by twu2 20060612 end
+
 /* Check whether an address is valid, return 1 if ok, 0 otherwise.
  * Unfortunately, multicasting with the FTP protocol is impossible,
  * you have to use things like MTP instead. So prohibit multicast.
@@ -2123,7 +2165,11 @@
     }
     switch (psvtype) {
     case 0:
-        if (STORAGE_FAMILY(force_passive_ip) == 0) {
+// add by twu2 20060612 begin
+        // if the connection from local subnet, don't do force passive ip convert
+        //if (STORAGE_FAMILY(force_passive_ip) == 0) {
+        if (is_local || STORAGE_FAMILY(force_passive_ip) == 0) {
+// add by twu2 20060612 end
             a = ntohl(STORAGE_SIN_ADDR(dataconn));
         } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET6) {
             (void) close(datafd);
@@ -4448,6 +4494,9 @@
         die(421, LOG_ERR, MSG_GETPEERNAME ": %s" , strerror(errno));
     }
     fourinsix(&peer);
+// add by twu2 20060612 begin
+    check_local_net(&peer);
+// add by twu2 20060612 end
     if (checkvalidaddr(&peer) == 0) {
         die(425, LOG_ERR, MSG_INVALID_IP);
     }
@@ -4486,6 +4535,9 @@
 #endif
     iptropize(&peer);
     logfile(LOG_INFO, MSG_NEW_CONNECTION, host);
+// add by twu2 20060612 begin
+    logfile(LOG_INFO, is_local == 1 ? "from local" : "from remote");
+// add by twu2 20060612 end
 
 #ifndef NO_BANNER
 # ifdef BORING_MODE
diff -Nur src.orig/globals.h src.patch/globals.h
--- src.orig/globals.h  2006-02-15 16:55:00.000000000 +0800
+++ src.patch/globals.h 2006-06-12 21:34:39.361685659 +0800
@@ -73,6 +73,9 @@
 GLOBAL0(signed char force_ls_a);
 GLOBAL0(struct sockaddr_storage peer);
 GLOBAL0(struct sockaddr_storage force_passive_ip);
+// add by twu2 20060612 begin
+GLOBAL(signed char is_local, 0);
+// add by twu2 20060612 end
 GLOBAL0(const char *force_passive_ip_s);
 GLOBAL0(unsigned short int peerdataport);
 GLOBAL0(double maxload);