運(yùn)維,請收好網(wǎng)絡(luò)工具中的瑞士軍刀,從此故障診斷不用愁!
Netcat 號稱 TCP/IP 的瑞士軍刀并非浪得虛名,以體積小(可執(zhí)行 200KB)功能靈活而著稱,在各大發(fā)行版中都默認(rèn)安裝,你可以用它來做很多網(wǎng)絡(luò)相關(guān)的工作,熟練使用它可以不依靠其他工具做一些很有用的事情。
最初作者是叫做“霍比特人”的網(wǎng)友 Hobbit hobbit@avian.org 于 1995 年在 UNIX 上以源代碼的形式發(fā)布,Posix 版本的 netcat 主要有 GNU 版本的 netcat 和 OpenBSD 的 netcat 兩者都可以在 debian/ubuntu 下面安裝,但是 Windows 下面只有 GNU 版本的 port。
不管是程序員還是運(yùn)維,熟悉這個命令都可以讓很多工作事半功倍,然而網(wǎng)上基本 90% 的 netcat 文章說的都是老版本的 OpenBSD 的 netcat,已經(jīng)沒法在主流 linux 上使用了,所以我們先要檢查版本:
在 debian/ubuntu 下面:
- readlink -f $(which nc)
看看,結(jié)果會有兩種:
- /bin/nc.traditional: 默認(rèn) GNU 基礎(chǔ)版本,一般系統(tǒng)自帶。
- /bin/nc.openbsd: openbsd 版本,強(qiáng)大很多。
都可以用 apt-get install nc-traditional 或者 apt-get install nc-openbsd 來選擇安裝。不管是 GNU 版本還是 OpenBSD 版本,都有新老的區(qū)別,主要是傳送文件時 stdin 發(fā)生 EOF 了,老版本會自動斷開,而新的 gnu/openbsd 還會一直連著,兩年前 debian jessie 時統(tǒng)一升過級,導(dǎo)致網(wǎng)上的所有教程幾乎同時失效。
下面主要以最新的 GNU 版本為主同時對照更強(qiáng)大的 openbsd 版本進(jìn)行說明。
端口測試
你在服務(wù)器 A主機(jī)(192.168.1.2) 上面 8080 端口啟動了一個服務(wù),有沒有通用的方法檢測服務(wù)的 TCP 端口是否啟動成功?或者在 B 主機(jī)上能不能正常訪問該端口?
進(jìn)一步,如果而 A 主機(jī)上用 netstat -an 發(fā)現(xiàn)端口成功監(jiān)聽了,你在 B 主機(jī)上的客戶端卻無法訪問,那么到底是服務(wù)錯誤還是網(wǎng)絡(luò)無法到達(dá)呢?我們當(dāng)然可以在 B 主機(jī)上用 telnet 探測一下:
- telnet 192.168.1.2 8080
但 telnet 并不是專門做這事情的,還需要額外安裝,所以我們在 B 主機(jī)上用 netcat:
- nc -vz 192.168.1.2 8080
即可,v 的意思是顯示多點(diǎn)信息(verbose),z 代表不發(fā)送數(shù)據(jù)。那么如果 B 主機(jī)連不上 A 主機(jī)的 8080 端口,此時你就該檢查網(wǎng)絡(luò)和安全設(shè)置了,如果連的上那么再去查服務(wù)日志去。
nc 命令后面的 8080 可以寫成一個范圍進(jìn)行掃描:
- nc -v -v -w3 -z 192.168.1.2 8080-8083
兩次 -v 是讓它報告更詳細(xì)的內(nèi)容,-w3 是設(shè)置掃描超時時間為 3 秒。
傳輸測試
你在配置 iptable 或者安全組策略,禁止了所有端口,但是僅僅開放了 8080 端口,你想測試一下該設(shè)置成功與否怎么測試?安裝個 nginx 改下端口,外面再用 chrome 訪問下或者 telnet/curl 測試下??還是 python -m 啟動簡單 http 服務(wù) ?其實(shí)不用那么麻煩,在需要測試的 A 主機(jī)上:
- nc -l -p 8080
這樣就監(jiān)聽了 8080 端口,然后在 B 主機(jī)上連接過去:
- nc 192.168.1.2 8080
兩邊就可以會話了,隨便輸入點(diǎn)什么按回車,另外一邊應(yīng)該會顯示出來,注意,openbsd 版本 netcat 用了 -l 以后可以省略 -p 參數(shù),寫做:nc -l 8080 ,但在 GNU netcat 下面無法運(yùn)行,所以既然推薦寫法是加上 -p 參數(shù),兩個版本都通用。
老版本的 nc 只要 CTRL+D 發(fā)送 EOF 就會斷開,新版本一律要 CTRL+C 結(jié)束,不管是服務(wù)端還是客戶端只要任意一邊斷開了,另一端也就結(jié)束了,但是 openbsd 版本的 nc 可以加一個 -k 參數(shù)讓服務(wù)端持續(xù)工作。
那么你就可以先用 nc 監(jiān)聽 8080 端口,再遠(yuǎn)端檢查可用,然后又再次隨便監(jiān)聽個 8081 端口,遠(yuǎn)端檢測不可用,說明你的安全策略配置成功了,完全不用安裝任何累贅的服務(wù)。
測試 UDP 會話
兩臺主機(jī) UDP 數(shù)據(jù)發(fā)送不過去,問題在哪呢?你得先確認(rèn)一下兩臺主機(jī)之間 UDP 可以到達(dá),這時候沒有 nginx 給你用了,怎么測試呢?用 python 寫個 udp 的 echo 服務(wù)??運(yùn)維不會認(rèn)你寫的工具的,即使連不通他也會認(rèn)為你的程序有 bug,于是 netcat 又登場了,在 A 主機(jī)上:
- nc -u -l -p 8080
監(jiān)聽 udp 的 8080 端口,然后 B 主機(jī)上連上去:
- nc -u 192.168.1.2 8080
然后像前面測試 tcp 的方法進(jìn)行檢測,結(jié)束了 CTRL+C 退出,看看一邊輸入消息另外一邊能否收到,收得到的話可能是你自己的服務(wù)原因,收不到的話把 nc 測試結(jié)果扔給運(yùn)維/系統(tǒng)管理員,讓他們趕快檢查網(wǎng)關(guān)和防火墻配置,系統(tǒng)自帶的工具測試的結(jié)果,既簡單又權(quán)威。
文件傳輸
你在一臺 B 主機(jī)上想往 A 主機(jī)上發(fā)送一個文件怎么辦?不能用 scp / szrz 的話?繼續(xù) python 寫個 http 上傳?裝個 ftpd 服務(wù)?不用那么麻煩,在 A 主機(jī)上監(jiān)聽端口:
- nc -l -p 8080 > image.jpg
然后在 B 主機(jī)上:
- nc 192.168.1.2 8080 < image.jpg
netcat 嘛,就是用于通過網(wǎng)絡(luò)把東西 cat 過去,注意,老版本 GNU / OpenBSD 的 netcat 再文件結(jié)束(標(biāo)準(zhǔn)輸入碰到 EOF),發(fā)送文件一端就會關(guān)閉連接,而新版本不會,你需要再開個窗口到 A 主機(jī)上看看接收下來的文件尺寸和源文件比較一下判斷傳輸是否結(jié)束。
當(dāng)傳輸完成后,你再任意一端 CTRL+C 結(jié)束它。對于新版 OpenBSD 的 netcat 有一個 -N 參數(shù),可以指明 stdin 碰到 EOF 就關(guān)閉連接(和老版本一致),我們寫作:
- /bin/nc.openbsd -N 192.168.1.2 8080 < image.jpg
你機(jī)器上的 nc 命令有可能指向 /bin/nc.traditional 或者 /bin/nc.openbsd 任意一個,這里顯示指明調(diào)用 openbsd 版本的 netcat。
這樣在 openbsd 新版本的 netcat 中使用 -N參數(shù),就不需要再開個終端去手工檢查傳輸是否完成,傳輸結(jié)束了就會自動退出。其實(shí) GNU 版本的 netcat 也有可以加個 -q0 參數(shù),達(dá)到和 openbsd 版本 -N 的效果:
/bin/nc.traditional -q0 192.168.1.2 8080 < image.jpg
只不過是 Linux 下面最新的 GNU netcat,對應(yīng) Windows 版本 沒有該參數(shù),所以從 Windows 傳文件過去時,少不了再開個終端看一下進(jìn)度,如果是 Linux 端發(fā)送就沒問題了。通過管道協(xié)作,搭配 tar 命令,還可以方便的傳一整個目錄過去,有興趣可以自己研究。
使用 netcat 這個系統(tǒng)默認(rèn)安裝的工具進(jìn)行文件傳輸,可以算作你保底的手段,當(dāng) scp/ftp 都沒法使用的情況下,你的一個殺手锏。
網(wǎng)速吞吐量測試
最簡單的方法,GNU 版本的 netcat 加上 -v -v 參數(shù)后,結(jié)束時會統(tǒng)計接收和發(fā)送多少字節(jié),那么此時 A 主機(jī)上顯示運(yùn)行 GNU 版本的 nc 監(jiān)聽端口:
- /bin/nc.traditional -v -v -n -l -p 8080 > /dev/null
加 n 的意思是不要解析域名,避免解析域名浪費(fèi)時間造成統(tǒng)計誤差,然后 B 主機(jī)上:
- time nc -n 192.168.1.2 8080 < /dev/zero
回車后執(zhí)行十秒鐘按 CTRL+C 結(jié)束,然后在 A 主機(jī)那里就可以看到接收了多少字節(jié)了,此時根據(jù) time 的時間自己做一下除法即可得知,注意 GNU 的 netcat 統(tǒng)計的數(shù)值是 32 位 int,如果傳輸太多就回環(huán)溢出成負(fù)數(shù)了。
對于 OpenBSD 版本的 nc 我們可以用管道搭配 dd 命令進(jìn)行統(tǒng)計,服務(wù)端運(yùn)行:
- nc -l -p 8080 > /dev/null
客戶端運(yùn)行 dd 搭配 nc:
- dd if=/dev/zero bs=1MB count=100 | /bin/nc.openbsd -n -N 192.168.1.2 8080
結(jié)束以后會有結(jié)果出來,注意這里使用了 -N 代表 stdin 碰到 EOF 后就關(guān)閉連接,這里凡是寫 nc 命令的地方,代表 GNU/OpenBSD 任意版本的 netcat 都可以,顯示的指明路徑,就代表必須使用特定版本的 netcat,上條命令等效的 GNU 版本是:
- dd if=/dev/zero bs=1MB count=100 | /bin/nc.traditional -n -q0 192.168.1.2 8080
其實(shí)上面兩種方法都把建立連接的握手時間以及 TCP 窗口慢啟動的時間給計算進(jìn)去了,不是特別精確,最精確的方式是搭配 pv 命令(監(jiān)控統(tǒng)計管道數(shù)據(jù)的速度),在 A 主機(jī)運(yùn)行:
- nc -l -p 8080 | pv
然后再 B 主機(jī)運(yùn)行:
- nc 192.168.1.2 8080 < /dev/zero
此時 A 主機(jī)那端持續(xù)收到 B 主機(jī)發(fā)送過來的數(shù)據(jù)并通過管道投遞給 pv 命令后,你就能看到實(shí)時的帶寬統(tǒng)計了,pv 會輸出一個實(shí)時狀態(tài):
- 353MiB 0:00:15 [22.4MiB/s] [ <=> ]
讓你看到最新的帶寬吞吐量,這是最準(zhǔn)確的吞吐量測試方法,在不需要 iperf 的情況下,直接使用 nc 就能得到一個準(zhǔn)確的數(shù)據(jù)。
系統(tǒng)后門
假設(shè)你用串口登錄到 A 主機(jī),上面十分原始,包管理系統(tǒng)都沒有,sshd/telnetd 都跑不起來,這時候你想用 B 主機(jī)通過網(wǎng)絡(luò)登錄 A 主機(jī)有沒有辦法?
GNU 版本的 netcat 有一個 -e 參數(shù),可以在連接建立的時候執(zhí)行一個程序,并把它的標(biāo)準(zhǔn)輸入輸出重定向到網(wǎng)絡(luò)連接上來,于是我們可以在 A 主機(jī)上 -e 一下 bash:
- /bin/nc.traditional -l -p 8080 -e /bin/bash
按回車打開系統(tǒng)后門,然后再 B 主機(jī)那里照常:
- nc 192.168.1.2 8080
你就可以在 B 主機(jī)上登錄 A 主機(jī)的 shell 了,操作完成 CTRL+C 結(jié)束。
對于 openbsd 版本的 netcat,-e 命令被刪除了,沒關(guān)系,我們可以用管道來完成,和剛才一樣,在 A 主機(jī)上:
- mkfifo /tmp/f
- cat /tmp/f | /bin/bash 2>&1 | /bin/nc.openbsd -l -p 8080 > /tmp/f
然后 B 主機(jī)和剛才一樣:
- nc 192.168.1.2 8080
即可訪問,用完注意將 /tmp/f 這個 fifo 文件刪除。
結(jié)束
netcat 就是可以在命令行直接的方式操作 tcp/udp 進(jìn)行原始的:監(jiān)聽,連接,數(shù)據(jù)傳輸?shù)裙ぷ?。然后搭配管道,?shí)現(xiàn)靈活多樣的功能,或者進(jìn)行各種網(wǎng)絡(luò)測試。
其實(shí)上面幾個例子,并不是說明 “netcat 可以干這些事情”而是通過舉例開一下腦洞,看看搭配管道的 netcat 究竟有多強(qiáng)。
還有很多其他用法,比如你可以用 netcat + shell script 寫一個 http 服務(wù)器,使用 fifo 搭配兩層 nc 可以實(shí)現(xiàn) tcp 端口轉(zhuǎn)發(fā),搭配 openssl 命令行工具和 nc 加管道可以把 ssl 的套接字解碼并映射成裸的 socket 端口供沒有 ssl 功能的工具訪問。
當(dāng)然你要說,這么多復(fù)雜的用法你記不住,大部分你都可以用專業(yè)軟件來代替,那至少你可以先嘗試使用 nc 來做 tcp/udp 端口測試,不要再用 telnet/chrome 來測試端口是否可用了,后者太過業(yè)余。其他功能可作為備份手段,在極端惡劣的環(huán)境下使用一下,也許能幫助到你很多;再你有心情的情況下可以研究下如何使用管道搭配其他工具進(jìn)行一些高階操作就行。