pure-ftpd with geoip


During the last few weeks we are experiencing compromised FTP accounts within our production. These accounts seem to be stolen from infected Windows client machines, infected by malware or trojans. As far as I know the issues, everyone of them is using Total Commander… TC seems to save the credentials in plain text form, unencrypted. Fine.

I have been going through pure-ftpd log to gather ips that had been used to upload files. I’ve found that most of them were outside our country, China, Romania, Russia, etc. So I decided to limit users set and allow only ips from Czech Republic. I wanted to go with iptables geoip module, which is working very fine. But I have found geoip patch for pure-ftpd. I have corrected it a little bit and finally created RPM packages for Centos4/5. You can find the packages within my repository. Feel free to use…

Packages

http://fs12.vsb.cz/hrb33/el5/hrb/stable/i386/repoview/pure-ftpd.html http://fs12.vsb.cz/hrb33/el5/hrb/stable/x86_64/repoview/pure-ftpd.html http://fs12.vsb.cz/hrb33/el4/hrb/stable/i386/repoview/pure-ftpd.html http://fs12.vsb.cz/hrb33/el4/hrb/stable/x86_64/repoview/pure-ftpd.html

The patch

diff -ur pure-ftpd-1.0.22/src/ftpd.c pure-ftpd-1.0.22-geoip/src/ftpd.c
--- pure-ftpd-1.0.22/src/ftpd.c 2009-09-17 09:38:04.000000000 +0200
+++ pure-ftpd-1.0.22-geoip/src/ftpd.c   2009-09-17 09:34:03.000000000 +0200
@@ -34,6 +34,8 @@
 # include "osx-extensions.h"
 #endif

+#include "GeoIP.h"
+
 #ifdef WITH\_GSSAPI
 # include "auth\_gssapi.h"
 #endif
@@ -4818,7 +4820,7 @@
 die(421, LOG\_ERR, MSG\_GETPEERNAME ": %s" , strerror(errno));
 }
 fourinsix(&peer);
-    if (checkvalidaddr(&peer) == 0) {
+    if (checkvalidaddr(&peer) == 0 || STORAGE\_FAMILY(ctrlconn) != AF\_INET) {
 die(425, LOG\_ERR, MSG\_INVALID\_IP);
 }
 #ifndef DONT\_LOG\_IP
@@ -4854,6 +4856,37 @@
 \*host = '?';
 host\[1\] = 0;
 #endif
+    do {
+        char line\[LINE\_MAX\];
+        GeoIP \*gi;
+        const char \*country;
+        char \*sep;
+        int found = 0;
+        FILE \*fp;
+
+        gi = GeoIP\_new(GEOIP\_STANDARD);
+        country = GeoIP\_country\_code\_by\_name(gi, host);
+        if (country == NULL || \*country == 0 ||
+            !(fp = fopen(CONFDIR "/pureftpd-restricted-countries.txt", "r"))) {
+            break;
+        }
+        while (fgets(line, sizeof line, fp) != NULL) {
+            if (\*line == '#') {
+                continue;
+            }
+            if ((sep = strchr(line, '\\n')) != NULL) {
+                \*sep = 0;
+            }
+            if (strcasecmp(line, country) == 0) {
+                found++;
+                break;
+            }
+        }
+        fclose(fp);
+        if (found == 0) {
+            die(425, LOG\_ERR, MSG\_INVALID\_IP);
+        }
+    } while(0);
 iptropize(&peer);
 logfile(LOG\_INFO, MSG\_NEW\_CONNECTION, host);

diff -ur pure-ftpd-1.0.22/src/Makefile.am pure-ftpd-1.0.22-geoip/src/Makefile.am
--- pure-ftpd-1.0.22/src/Makefile.am    2006-04-25 10:15:54.000000000 +0200
+++ pure-ftpd-1.0.22-geoip/src/Makefile.am      2009-09-17 09:37:14.000000000 +0200
@@ -16,7 +16,7 @@

 pure\_ftpd\_LDADD = \\
        ../puredb/src/libpuredb\_read.a \\
-       @LDAP\_SSL\_LIBS@ @GETLOADAVG\_LIBS@ @BONJOUR\_LDADD@
+       @LDAP\_SSL\_LIBS@ @GETLOADAVG\_LIBS@ @BONJOUR\_LDADD@ -lGeoIP

 pure\_ftpd\_CFLAGS = -DINCLUDE\_IO\_WRAPPERS=1

diff -ur pure-ftpd-1.0.22/src/Makefile.in pure-ftpd-1.0.22-geoip/src/Makefile.in
--- pure-ftpd-1.0.22/src/Makefile.in    2006-04-25 10:45:12.000000000 +0200
+++ pure-ftpd-1.0.22-geoip/src/Makefile.in      2009-09-17 09:35:43.000000000 +0200
@@ -221,7 +221,7 @@
 target\_alias = @target\_alias@
 pure\_ftpd\_LDADD = \\
        ../puredb/src/libpuredb\_read.a \\
-       @LDAP\_SSL\_LIBS@ @GETLOADAVG\_LIBS@ @BONJOUR\_LDADD@
+       @LDAP\_SSL\_LIBS@ @GETLOADAVG\_LIBS@ @BONJOUR\_LDADD@ -lGeoIP

 pure\_ftpd\_CFLAGS = -DINCLUDE\_IO\_WRAPPERS=1
 pure\_ftpd\_SOURCES = \\
ftp  geoip  patch