這裡示範如何使用 bash 指令稿開啟 TCP/UDP 的 socket,進行各種網路診斷工作。
作為網管或是 Linux 系統管理者,使用 netcat
、wget
或 curl
這類的指令檢查遠端伺服器的網路服務應該算是基本技能,而且是時常會需要做的工作之一,但是如果遇到系統上沒有這類的工具可用時,我們就可以改用 bash shell 內建的一些功能來達到類似的效果。
在 Linux 系統上我們可以藉由
/dev/tcp
與 /dev/udp
底下的設備檔來開啟 TCP 與 UDP 的網路連線,以下是一些開啟 TCP 與 UDP 連線的 bash 指令稿範例。
Bash 開啟 TCP/UCP 連線
在 bash 中,我們可以使用以下這個語法來開啟 TCP 或是 UDP 的 socket:
# 開啟輸入與輸出的 socket exec FILE_DESCRIPTOR<>/dev/PROTOCOL/HOST/PORT
這個指令各部份的意義如下:
FILE_DESCRIPTOR
- socket 的檔案代碼,值為大於或等於零的整數,而
0
、1
與2
分別代表系統的標準輸入(stdin
)、標準輸出(stdout
)與標準錯誤(stderr
),所以我們能使用的值是從3
開始。 <>
- 代表此 socket 同時以讀取與寫入的模式開啟。
PROTOCOL
- 傳輸協定,可為
tcp
或是udp
。 HOST
- 主機名稱或是 IP 位址。
PORT
- 連接埠號碼。
若要關閉 socket,則執行:
# 關閉輸入 socket exec FILE_DESCRIPTOR<&- # 關閉輸出 socket exec FILE_DESCRIPTOR>&-
測試網頁伺服器
以下是一個實際的範例,這個範例會使用 bash 的只令開啟連線至 Google 網頁的 socket,下載網頁資料:
#!/bin/bash # 開啟連線至 Google 網頁的 socket exec 3<>/dev/tcp/www.google.com.tw/80 # 送出 HTTP 請求 echo -e "GET / HTTP/1.1\n\n" >&3 # 接收網頁內容,1 秒後自動停止接收資料 timeout 1 cat <&3 # 關閉輸入與輸出 socket exec 3<&- exec 3>&-
這個範例可分為四個部份:
- 開啟一個 TCP socket 連到
www.google.com.tw
這台主機的80
連接埠,將檔案代碼設定為3
。 - 使用
echo
將 HTTP 請求的內容透過檔案代碼3
送給 Google 網頁伺服器。 - 從檔案代碼
3
讀取來自於 Google 網頁伺服器的網頁資料,用cat
輸出。 - 關閉輸入與輸出的 socket。
執行之後就會輸出 Google 網頁的原始 HTML 碼。
查詢 SSH 伺服器版本
這是一個檢查 SSH 伺服器版本的範例,用法大同小異:
#!/bin/bash # 開啟 socket,連線至 192.168.0.1 的 SSH 伺服器 exec 3</dev/tcp/192.168.0.1/22 # 接收 SSH 的版本資訊,1 秒後自動停止接收資料 timeout 1 cat <&3 # 關閉輸入與輸出 socket exec 3<&- exec 3>&-
而上面這個檢查 SSH 版本的範例可以改寫為以下這個精簡的版本:
#!/bin/bash # 檢查 192.168.0.1 的 SSH 伺服器版本 timeout 1 cat </dev/tcp/192.168.0.1/22
取得時間
這是一個透過 DAYTIME 協定,從伺服器取得目前時間的範例:
#!/bin/bash # 取的時間資訊 cat </dev/tcp/time.nist.gov/13
檢查網頁連線
這個範例可以用來檢查網頁伺服器是否有正常運作,也就是測試伺服器的 80
連接埠是否可以正常連接:
#!/bin/bash # 伺服器資訊 HOST=www.mit.edu PORT=80 (echo >/dev/tcp/${HOST}/${PORT}) &>/dev/null if [ $? -eq 0 ]; then echo "伺服器連接成功。" else echo "伺服器連接失敗!" fi
掃描連接埠
這個範例可以用來掃描主機的連接埠(port),看看哪些服務有開啟:
#!/bin/bash # 要掃描的主機 HOST=192.168.0.1 # 要掃描的連接埠範圍 PORT_BEGIN=1 PORT_END=65535 for ((port=$PORT_BEGIN; port<=$PORT_END; port++)) do (echo >/dev/tcp/$HOST/$port) >/dev/null 2>&1 && echo "連接埠 $port 有開啟" done