Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

讓 pure-ftpd 的 -P (--forcepassiveip) 參數, 只能用在遠端的連線
post by tommy @ 12 六月, 2006 23:07
今天把伺服器中的 vsftpd 換成 pureftpd, 也順便把 TLS 的功能給加上. 發現在加上 TLS 之後, 無論是 active 還是 passive, 都無法取得檔案列表, 也無法傳送檔案了.

查了一下原因, 終於想到在用了 TLS 加密之後, 位於 firewall 後端的 ftp 伺服器, 在我使用的 netfilter 中, 就算加上 ftp 的模組, 也看不到加密的內容, 自然不會幫我做 ftp 協定中, 在 passive mode 所傳送的 ip 位置的轉換. 所以我在遠端看到的 ip 還是那台 ftp 伺服器的 local ip, 自然連不上了.

後來想說, 改成 active mode, 總應該可以吧. 但是.... 公司的 IPX 上頭, 在使用 active mode 連線時, 並不會把我這邊的 ip 轉換成遠端的 ip 再送出, 所以.... ftp 伺服器那端的程式, 想連到我機器的 local ip, 自然也連不上了. (如果你的 firewall 支援 active mode, 應該就不會有這個問題, 我回宿舍使用 adsl 時, 透過 wireless router 時, 使用 active mode 就可以正常連線)

查了一下 pureftpd 的文件, 發現可以使用 -P (--forcepassiveip) 來指定在 passive mode 時, 要使用的 ip, 加上 -p (--passiveportrange) 來指定使用的 port. 如此, 我只要在 firewall 上頭, 把這個 range 的 port 都轉向該主機, 就算 netfilter 看不懂那些加密的內容, 也可以讓我在遠端使用 TLS 來連線了.

原本看起來似乎解決了我的問題, 但是... 後來, 發現這樣處理之後, 在 local 端的機器如果連線之後, 使用 passive mode, 反而會收到所設定的那個外部 ip, 結果... 自然也無法取得資料. (我記得就算用外部的 ip 在內部網路連線, 我的 firewall 設定應該也會做 NAT 轉換來連線才對啊, 看來要找時間檢查看看)

所以... 就改了 pureftpd 的程式, 讓這個程式檢查 /etc/localnet 的內容, 看看遠端的ip 是否在同一個 subnet 之中, 如果是, 就不要使用 -P 所設定的參數. 這樣子似乎就解決了我的問題了.

這個 patch 如下:

diff -Nur src.orig/ftpd.c src/ftpd.c
--- src.orig/ftpd.c 2006-06-12 18:44:25.000000000 +0800
+++ src/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/globals.h
--- src.orig/globals.h 2006-02-15 16:55:00.000000000 +0800
+++ src/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);
 

這個 patch, 可以由這兒抓取: http://www.teatime.com.tw/~tommy/mypatch/pureftpd_no_force_passive_ip_for_local.patch

而 /etc/locanet 的內容, 就是 AAA.BBB.CCC.DDD/WWW.XXX.YYY.ZZZ 之類的格式. 如: 192.168.0.0/255.255.0.0

如果你有多個 local 網路, 就每行寫一個. (如果格式不對, 會被忽略) 

 

Del.icio.us Furl HEMiDEMi Technorati MyShare
commons icon [1] Re:讓 pure-ftpd 的 -P (--forcepassiveip) 參數, 只能用在遠端的連線 [ 回覆 ]

最近我也在煩惱這個問題,剛好看到你的網頁,解決了我的困擾,真是太棒了!

迴響
暱稱:
標題:
個人網頁:
電子郵件:
迴響

  

Bad Behavior 已經阻擋了 95 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS