運維,請收好網絡工具中的瑞士軍刀,從此故障診斷不用愁!

Netcat 號稱 TCP/IP 的瑞士軍刀並非浪得虛名,以體積小(可執行 200KB)功能靈活而著稱,在各大發行版中都默認安裝,你可以用它來做很多網絡相關的工作,熟練使用它可以不依靠其他工具做一些很有用的事情。

最初作者是叫做“霍比特人”的網友 Hobbit [email protected] 於 1995 年在 UNIX 上以源代碼的形式發佈,Posix 版本的 netcat 主要有 GNU 版本的 netcat 和 OpenBSD 的 netcat 兩者都可以在 debian/ubuntu 下面安裝,但是 Windows 下面只有 GNU 版本的 port。

不管是程序員還是運維,熟悉這個命令都可以讓很多工作事半功倍,然而網上基本 90% 的 netcat 文章說的都是老版本的 OpenBSD 的 netcat,已經沒法在主流 linux 上使用了,所以我們先要檢查版本:

在 debian/ubuntu 下面:

<code>readlink -f $(which nc)/<code>


看看,結果會有兩種:

  • /bin/nc.traditional: 默認 GNU 基礎版本,一般系統自帶。
  • /bin/nc.openbsd: openbsd 版本,強大很多。

都可以用 apt-get install nc-traditional 或者 apt-get install nc-openbsd 來選擇安裝。不管是 GNU 版本還是 OpenBSD 版本,都有新老的區別,主要是傳送文件時 stdin 發生 EOF 了,老版本會自動斷開,而新的 gnu/openbsd 還會一直連著,兩年前 debian jessie 時統一升過級,導致網上的所有教程幾乎同時失效。

下面主要以最新的 GNU 版本為主同時對照更強大的 openbsd 版本進行說明。

端口測試

你在服務器 A主機(192.168.1.2) 上面 8080 端口啟動了一個服務,有沒有通用的方法檢測服務的 TCP 端口是否啟動成功?或者在 B 主機上能不能正常訪問該端口?

進一步,如果而 A 主機上用 netstat -an 發現端口成功監聽了,你在 B 主機上的客戶端卻無法訪問,那麼到底是服務錯誤還是網絡無法到達呢?我們當然可以在 B 主機上用 telnet 探測一下:

<code>telnet 192.168.1.2 8080/<code>


但 telnet 並不是專門做這事情的,還需要額外安裝,所以我們在 B 主機上用 netcat:

<code>nc -vz 192.168.1.2 8080/<code>


即可,v 的意思是顯示多點信息(verbose),z 代表不發送數據。那麼如果 B 主機連不上 A 主機的 8080 端口,此時你就該檢查網絡和安全設置了,如果連的上那麼再去查服務日誌去。

nc 命令後面的 8080 可以寫成一個範圍進行掃描:

<code>nc -v -v -w3 -z 192.168.1.2 8080-8083/<code>


兩次 -v 是讓它報告更詳細的內容,-w3 是設置掃描超時時間為 3 秒。

傳輸測試

你在配置 iptable 或者安全組策略,禁止了所有端口,但是僅僅開放了 8080 端口,你想測試一下該設置成功與否怎麼測試?安裝個 nginx 改下端口,外面再用 chrome 訪問下或者 telnet/curl 測試下??還是 python -m 啟動簡單 http 服務 ?其實不用那麼麻煩,在需要測試的 A 主機上:

<code>nc -l -p 8080/<code>


這樣就監聽了 8080 端口,然後在 B 主機上連接過去:

<code>nc 192.168.1.2 8080/<code>


兩邊就可以會話了,隨便輸入點什麼按回車,另外一邊應該會顯示出來,注意,openbsd 版本 netcat 用了 -l 以後可以省略 -p 參數,寫做:nc -l 8080 ,但在 GNU netcat 下面無法運行,所以既然推薦寫法是加上 -p 參數,兩個版本都通用。

老版本的 nc 只要 CTRL+D 發送 EOF 就會斷開,新版本一律要 CTRL+C 結束,不管是服務端還是客戶端只要任意一邊斷開了,另一端也就結束了,但是 openbsd 版本的 nc 可以加一個 -k 參數讓服務端持續工作。

那麼你就可以先用 nc 監聽 8080 端口,再遠端檢查可用,然後又再次隨便監聽個 8081 端口,遠端檢測不可用,說明你的安全策略配置成功了,完全不用安裝任何累贅的服務。

測試 UDP 會話

兩臺主機 UDP 數據發送不過去,問題在哪呢?你得先確認一下兩臺主機之間 UDP 可以到達,這時候沒有 nginx 給你用了,怎麼測試呢?用 python 寫個 udp 的 echo 服務??運維不會認你寫的工具的,即使連不通他也會認為你的程序有 bug,於是 netcat 又登場了,在 A 主機上:


<code>nc -u -l -p 8080/<code>


監聽 udp 的 8080 端口,然後 B 主機上連上去:

<code>nc -u 192.168.1.2 8080/<code>


然後像前面測試 tcp 的方法進行檢測,結束了 CTRL+C 退出,看看一邊輸入消息另外一邊能否收到,收得到的話可能是你自己的服務原因,收不到的話把 nc 測試結果扔給運維/系統管理員,讓他們趕快檢查網關和防火牆配置,系統自帶的工具測試的結果,既簡單又權威。

文件傳輸

你在一臺 B 主機上想往 A 主機上發送一個文件怎麼辦?不能用 scp / szrz 的話?繼續 python 寫個 http 上傳?裝個 ftpd 服務?不用那麼麻煩,在 A 主機上監聽端口:

<code>nc -l -p 8080 > image.jpg/<code>


然後在 B 主機上:

<code>nc 192.168.1.2 8080 /<code>


netcat 嘛,就是用於通過網絡把東西 cat 過去,注意,老版本 GNU / OpenBSD 的 netcat 再文件結束(標準輸入碰到 EOF),發送文件一端就會關閉連接,而新版本不會,你需要再開個窗口到 A 主機上看看接收下來的文件尺寸和源文件比較一下判斷傳輸是否結束。

當傳輸完成後,你再任意一端 CTRL+C 結束它。對於新版 OpenBSD 的 netcat 有一個 -N 參數,可以指明 stdin 碰到 EOF 就關閉連接(和老版本一致),我們寫作:

<code>/bin/nc.openbsd -N 192.168.1.2 8080 /<code>


你機器上的 nc 命令有可能指向 /bin/nc.traditional 或者 /bin/nc.openbsd 任意一個,這裡顯示指明調用 openbsd 版本的 netcat。

這樣在 openbsd 新版本的 netcat 中使用 -N參數,就不需要再開個終端去手工檢查傳輸是否完成,傳輸結束了就會自動退出。其實 GNU 版本的 netcat 也有可以加個 -q0 參數,達到和 openbsd 版本 -N 的效果:

<code>/bin/nc.traditional -q0 192.168.1.2 8080 /<code>


只不過是 Linux 下面最新的 GNU netcat,對應 Windows 版本 沒有該參數,所以從 Windows 傳文件過去時,少不了再開個終端看一下進度,如果是 Linux 端發送就沒問題了。通過管道協作,搭配 tar 命令,還可以方便的傳一整個目錄過去,有興趣可以自己研究。

使用 netcat 這個系統默認安裝的工具進行文件傳輸,可以算作你保底的手段,當 scp/ftp 都沒法使用的情況下,你的一個殺手鐧。

網速吞吐量測試

最簡單的方法,GNU 版本的 netcat 加上 -v -v 參數後,結束時會統計接收和發送多少字節,那麼此時 A 主機上顯示運行 GNU 版本的 nc 監聽端口:


<code>/bin/nc.traditional -v -v -n -l -p 8080 > /dev/null/<code>


加 n 的意思是不要解析域名,避免解析域名浪費時間造成統計誤差,然後 B 主機上:

time nc -n 192.168.1.2 8080 < /dev/zero

回車後執行十秒鐘按 CTRL+C 結束,然後在 A 主機那裡就可以看到接收了多少字節了,此時根據 time 的時間自己做一下除法即可得知,注意 GNU 的 netcat 統計的數值是 32 位 int,如果傳輸太多就回環溢出成負數了。

對於 OpenBSD 版本的 nc 我們可以用管道搭配 dd 命令進行統計,服務端運行:

<code>nc -l -p 8080 > /dev/null/<code>


客戶端運行 dd 搭配 nc:

<code>dd if=/dev/zero bs=1MB count=100 | /bin/nc.openbsd -n -N 192.168.1.2 8080/<code>


結束以後會有結果出來,注意這裡使用了 -N 代表 stdin 碰到 EOF 後就關閉連接,這裡凡是寫 nc 命令的地方,代表 GNU/OpenBSD 任意版本的 netcat 都可以,顯示的指明路徑,就代表必須使用特定版本的 netcat,上條命令等效的 GNU 版本是:

<code>dd if=/dev/zero bs=1MB count=100 | /bin/nc.traditional -n -q0 192.168.1.2 8080/<code>


其實上面兩種方法都把建立連接的握手時間以及 TCP 窗口慢啟動的時間給計算進去了,不是特別精確,最精確的方式是搭配 pv 命令(監控統計管道數據的速度),在 A 主機運行:

<code>nc -l -p 8080 | pv/<code>


然後再 B 主機運行:

<code>nc 192.168.1.2 8080 /<code>


此時 A 主機那端持續收到 B 主機發送過來的數據並通過管道投遞給 pv 命令後,你就能看到實時的帶寬統計了,pv 會輸出一個實時狀態:

<code>353MiB 0:00:15 [22.4MiB/s] [          <=>  ]/<code>


讓你看到最新的帶寬吞吐量,這是最準確的吞吐量測試方法,在不需要 iperf 的情況下,直接使用 nc 就能得到一個準確的數據。

系統後門

假設你用串口登錄到 A 主機,上面十分原始,包管理系統都沒有,sshd/telnetd 都跑不起來,這時候你想用 B 主機通過網絡登錄 A 主機有沒有辦法?

GNU 版本的 netcat 有一個 -e 參數,可以在連接建立的時候執行一個程序,並把它的標準輸入輸出重定向到網絡連接上來,於是我們可以在 A 主機上 -e 一下 bash:

<code>/bin/nc.traditional -l -p 8080 -e /bin/bash/<code>


按回車打開系統後門,然後再 B 主機那裡照常:

<code>nc 192.168.1.2 8080/<code>


你就可以在 B 主機上登錄 A 主機的 shell 了,操作完成 CTRL+C 結束。

對於 openbsd 版本的 netcat,-e 命令被刪除了,沒關係,我們可以用管道來完成,和剛才一樣,在 A 主機上:

<code>mkfifo /tmp/f
cat /tmp/f | /bin/bash 2>&1 | /bin/nc.openbsd -l -p 8080 > /tmp/f/<code>


然後 B 主機和剛才一樣:

<code>nc 192.168.1.2 8080/<code>


即可訪問,用完注意將 /tmp/f 這個 fifo 文件刪除。

結束

netcat 就是可以在命令行直接的方式操作 tcp/udp 進行原始的:監聽,連接,數據傳輸等工作。然後搭配管道,實現靈活多樣的功能,或者進行各種網絡測試。

其實上面幾個例子,並不是說明 “netcat 可以幹這些事情”而是通過舉例開一下腦洞,看看搭配管道的 netcat 究竟有多強。

還有很多其他用法,比如你可以用 netcat + shell>

當然你要說,這麼多複雜的用法你記不住,大部分你都可以用專業軟件來代替,那至少你可以先嚐試使用 nc 來做 tcp/udp 端口測試,不要再用 telnet/chrome 來測試端口是否可用了,後者太過業餘。其他功能可作為備份手段,在極端惡劣的環境下使用一下,也許能幫助到你很多;再你有心情的情況下可以研究下如何使用管道搭配其他工具進行一些高階操作就行。


分享到:


相關文章: