ByteScope

21

連接埠 21 · FTP

TCPIANA 有指派檔案傳輸

FTP 的控制連線——指令和三位數的回應碼走的是這個連接埠,檔案本身則走另一條連線,而那條用的連接埠沒有人告訴過你的防火牆。

查出是誰占用連接埠 21

照你的系統挑一行貼上去執行。它會直接印出占著這個連接埠的行程,以及它綁在哪個位址上——通常看到這兩件事答案就出來了。

從機器外面確認一次

`nmap -Pn -p 21 files.example.com` 從主機外面問了唯一重要的那個問題,而 `-Pn` 會跳過主機探索,所以不回 ping 的機器照樣掃得到。答案的意思由 nmap 自己的定義決定:`open` 是那個連接埠上真的有應用程式在接受連線;`closed` 是連接埠到得了、也回了話,但沒有應用程式在監聽;`filtered` 是封包過濾讓探測封包根本到不了連接埠,所以 nmap 分不出來它其實是前面哪一種。加 `--reason` 可以看到是什麼決定了結果——closed 回的是 reset,filtered 是一片安靜;加 `-sV` 則會讓 nmap 讀 `220` 那句招呼,通常直接報出 daemon 名稱和版本。這個連接埠有一點要特別注意:這次掃描完全沒有講到資料連線,因為被動模式傳檔用的是掃描根本沒碰的高位連接埠。21 顯示 `open`、下載卻卡在零位元組,這兩件事完全可以同時成立。只掃你自己負責的主機。

連不上 21 的時候怎麼讀

你看到的訊息代表什麼
ftp: connect: Connection refused封包送到了主機,而它的核心回了一個 reset,因為沒有任何行程占著連接埠 21。可能是 daemon 停了、啟動失敗,或綁在一個不含你撥過去那個位址的地方。上面那些探測指令要在伺服器上跑,不是在你的筆電上,而且不要只確認有那一行,要把綁定位址讀出來。
The client sits silent for tens of seconds, then reports Connection timed out完全沒有回應。有個封包過濾器正安靜地丟掉你的 SYN——雲端的安全群組、主機上的防火牆,或路徑中間的網路 ACL。被拒絕會立刻回來,被丟掉要等,這段等待本身就是診斷。從外面用 `nmap --reason` 確認:`filtered` 是丟掉,`closed` 是拒絕。
425 Can't open data connection連接埠 21 沒問題。你已經登入、伺服器也收下了指令,不然不會回你一個帶號碼的回應。壞掉的是第二條連線。被動模式下,可能是伺服器給了你一個高位連接埠而你的防火牆不放你出去,也可能是伺服器自己那段被動範圍沒有對外開。主動模式下,則是伺服器要回撥給你的用戶端,被中間某一段擋住了。切換模式看哪一邊會通:多數用戶端用 `passive` 切換,而 `curl` 除非你加 `-P -`,否則一律走被動。
500 Illegal PORT command伺服器直接拒絕主動模式,現在很多都這樣做,因為那個回撥是眾所周知的濫用途徑。改用被動模式。另外還有一種長得一樣的情況:NAT 改寫了 `PORT` 指令裡的位址,伺服器看到的位址跟它正在講話的那條控制連線對不起來,於是刻意擋掉。
227 Entering Passive Mode reports an address you cannot route to在 NAT 後面的伺服器如果沒被告知自己的對外位址,就會把私有位址原封不動廣播出去,於是用戶端很老實地去連 10.0.0.5 這種地方然後卡死。要修的是伺服器端:設定它該廣播的外部位址,或改用擴充的 `EPSV`,那個只回連接埠,位址沿用控制連線的。
530 Login incorrect這裡沒有一件事跟連接埠有關。控制連線已經建立,伺服器是讀完帳密之後才拒絕你的。不是帳號或密碼錯,就是帳號存在但被單獨擋掉 FTP——shell 設成 `/usr/sbin/nologin`、名字被列在伺服器的拒絕清單裡,或設定只允許被 chroot 的虛擬使用者。
500 OOPS: could not bind listening IPv4 socket / bind: Address already in use`EADDRINUSE`:已經有東西占著這個 socket,而 daemon 是在啟動途中就結束,不是跑一跑才掛。通常是另一個套件裝進來的第二套 FTP 伺服器,或是把 21 發布到主機上的容器。動手砍之前先用上面的指令找出持有者;如果一兩分鐘後連接埠自己空出來,那是前一個行程留下的 `TIME_WAIT` socket,本來就不需要砍任何東西。
bind: Permission denied while starting the server on 21這一個是真的在講特權連接埠:類 Unix 系統上 1024 以下需要 root,而 21 就在裡面。用 init 系統以 root 啟動 daemon,或在 Linux 上給那支執行檔 `CAP_NET_BIND_SERVICE`,再不然監聽高位連接埠再轉導。不過在 SELinux 或 AppArmor 的主機上,政策拒絕那支執行檔綁定時也會吐同一句話,所以先看稽核紀錄再認定是 1024 的規則。

連接埠 21 上跑的是什麼

IANA 依 RFC 959 把 21 指派給 `ftp`,也就是 File Transfer Protocol 的控制連線,隔壁的 20 則登記成 `ftp-data`。註冊表上 TCP 和 UDP 都有,實際在用的只有 TCP。關於這個連接埠,最值得先知道的就是「連線有兩條」這件事。工作階段開在 21 上,你打的每一個 `USER`、`PASS`、`LIST`、`RETR`,以及伺服器回的數字碼,全都以看得懂的 ASCII 在上面跑——但檔案內容一個位元組都不會走這裡。每次傳檔都會另外開一條 TCP 連線,而由哪一邊撥出去,決定了它過不過得了防火牆。主動模式是用戶端送 `PORT`(RFC 2428 則是 `EPRT`),由伺服器反過來連回用戶端,這在現在幾乎所有 NAT 和用戶端防火牆都會被擋掉。被動模式是用戶端送 `PASV`,伺服器回 `227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)`,最後兩個數字就是連接埠,實際值是 `p1 * 256 + p2`;或是回 `229 Entering Extended Passive Mode (|||port|)`,然後由用戶端撥過去。現在大家預設都走被動,這也是為什麼 FTP 伺服器不能只開 21,還得把一整段資料用的連接埠範圍一起開出來。再來就是把多數人帶到這一頁的命名陷阱:FTPS 和 SFTP 不是同一個東西的兩種寫法。FTPS 是 RFC 4217 幫 FTP 加上 TLS——用戶端在同一個 21 上送 `AUTH TLS`,之後整段就是加密的;至於從第一個位元組就加密、完全不需要 `AUTH` 的舊式做法,IANA 另外把 990 指派成 `ftps`。而 SFTP 怎麼看都不是 FTP:它是連接埠 22 上 SSH 的一個子系統,跟 FTP 沒有共用任何指令、任何回應碼,也沒有第二條資料連線,你只需要開 22 這一個連接埠。

連接埠 21 該不該對外開

不要把明文 FTP 放到網際網路上。密碼在 21 上是明文過去的,跟 telnet 一模一樣,而公開的監聽者幾小時內就會被全網掃描器找到,接著被拿匿名存取和廠商預設值一個個試。FTP 伺服器比別人更會漏,通常是兩個習慣造成的:為了給某一個檔案而打開的匿名讀取,之後就再也沒關掉;還有沒有做每位使用者的 chroot,於是通過認證的帳號可以一路走出自己的目錄。如果你只是要把檔案交給某個人,443 的 HTTPS 做同一件事,暴露面小得多。如果你要的是互動式的檔案操作,走 SSH 的 SFTP 只要開一個連接埠,還附帶主機金鑰驗證,指令和內容一起加密。當 FTP 真的非留不可——某台設備、某具實驗儀器、某個不肯改的合作對象——就強制使用帶 `AUTH TLS` 的明確式 FTPS,同時要知道:保護控制連線並不等於保護傳輸。資料連線只有在用戶端另外要求 `PROT P` 時才會加密,所以完全可能出現登入走 TLS、檔案卻是明文送出去的情況。把被動模式的連接埠範圍在伺服器設定裡釘死,讓防火牆規則是一扇窄窗而不是整段高位範圍;再用來源位址收一次;還有,與其相信 NAT 幫你擋著,不如去看路由器實際轉發了什麼。

服務
FTP
傳輸協定
TCP
登記狀態
IANA 有指派
分類
檔案傳輸

站上可以搭配的工具

這些全都在你的瀏覽器裡跑,不會上傳任何東西。

相關連接埠

查 21 的時候,通常也會順手看一下這幾個。

常見問題

明明就有東西在用,指令卻什麼都沒印出來?

幾乎都是權限問題。lsofss 會列出 socket,但別人的行程它不會顯示所有者,所以由系統帳號、容器執行環境或 launchd 啟動的服務,在你補上 sudo 之前就只是一個沒有主人的監聽項。Windows 則是反過來:netstat 什麼都沒有,綁定卻還是失敗,那代表這個號碼落在 Hyper-V、WSL2 或 Docker Desktop 開機時預留的範圍裡。

占著連接埠的那個行程可以直接砍掉嗎?

先看清楚它是什麼。沒收乾淨的開發伺服器砍掉沒事;正在寫入的資料庫不行,其他東西依賴的系統服務也不行。如果持有者是容器,請停容器,不要砍主機看到的那個行程——砍了執行環境只會把它拉起來。遇到真的不能動的,把自己的服務換一個連接埠反而更快。

為什麼本機連得到,別台機器就連不到?

因為它綁在 127.0.0.1 而不是 0.0.0.0。每一頁的指令之所以會把綁定位址跟行程名一起印出來,就是為了這件事:綁在回送位址上的服務,不管防火牆怎麼設,都只有這台機器自己連得到。現在不少框架是刻意這樣預設的,所以通常是一個參數的問題,不是 bug。如果已經是 0.0.0.0 還是不通,下一個要懷疑的就是主機防火牆或雲端的安全群組。

把服務換到冷門的連接埠會比較安全嗎?

幾乎沒有幫助。掃全網的機器持續在掃整段範圍,換號碼買到的是幾個小時,不是安全,代價卻是每個同事都得記住它。它確實能讓針對預設埠的無差別掃描少污染一點日誌,這算是實際但有限的好處。真正會改變結果的是認證、限制來源位址的防火牆,以及一開始就不要讓它對外。

連接埠 21 還是卡住嗎?看完整的連接埠對照表,或是回到上面,從你實際看到的那行錯誤往回追。