個人筆記,不保證正確!
文中的命令均在 macOS Big Sur 和 Opensuse Tumbleweed 上測試通過
socat & netcat
netcat(network cat) 是一個歷史悠久的網路工具包,被稱作 TCP/IP 的瑞士軍刀,各大 Linux 發行版都有預設安裝 openbsd 版本的 netcat,它的命令列名稱為 nc
.
而 socat(socket cat),官方文件描述它是 "netcat++" (extended design, new implementation)
,專案比較活躍,kubernetes-client(kubectl) 底層就是使用的它做各種流量轉發。
在不方便安裝 socat 的環境中,我們可以使用系統自帶的 netcat.
而在其他環境,可以考慮優先使用 socat.
一、簡介
socat 的基本命令格式:
socat [引數] 地址1 地址2
給 socat 提供兩個地址,socat 乾的活就是把兩個地址的流對接起來。左邊地址的輸出傳給右邊,同時又把右邊地址的輸出傳給左邊,也就是一個雙向的資料管道。
聽起來好像沒啥特別的,但是實際上計算機網路乾的活也就是資料傳輸而已,卻影響了整個世界,不可小覷它的功能。
socat 支援非常多的地址型別:-
/stdio,TCP, TCP-LISTEN, UDP, UDP-LISTEN, OPEN, EXEC, SOCKS, PROXY 等等,可用於埠監聽、連結,檔案和程式讀寫,代理橋接等等。
socat 的功能就是這麼簡單,命令列引數也很簡潔,唯一需要花點精力學習的就是它各種地址的定義和搭配寫法。
而 netcat 定義貌似沒這麼嚴謹,可以簡單的理解為網路版的 cat 命令 2333
二、安裝方法
各發行版都自帶 netcat,包名通常為 nc-openbsd
,因此這裡只介紹 socat 的安裝方法:
# Debian/Ubuntu
sudo apt install socat
# CentOS/RedHat
sudo yum install socat
# macOS
brew install socat
其他發行版基本也都可以使用包管理器安裝 socat
三、常用命令
1. 網路除錯
1.1 檢測遠端埠的可連線性(確認防火牆沒問題)
以前你可能學過如何用 telnet 來做這項測試,不過現在很多發行版基本都不自帶 telnet 了,還需要額外安裝。
telnet 差不多已經快壽終正寢了,還是建議使用更專業的 socat/netcat
使用 socat/netcat 檢測遠端埠的可連線性:
# -d[ddd] 增加日誌詳細程度,-dd Prints fatal, error, warning, and notice messages.
socat -dd - TCP:192.168.1.252:3306
# -v 顯示詳細資訊
# -z 不傳送資料,效果為立即關閉連線,快速得出結果
nc -vz 192.168.1.2 8080
# -vv 顯示更詳細的內容
# -w2 超時時間設為 2 秒
# 使用 nc 做簡單的埠掃描
nc -vv -w2 -z 192.168.1.2 20-500
1.2 測試本機埠是否能正常被外部訪問(檢測防火牆、路由)
在本機監聽一個 TCP 埠,接收到的內容傳到 stdout,同時將 stdin 的輸入傳給客戶端:
# 服務端啟動命令,socat/nc 二選一
socat TCP-LISTEN:7000 -
# -l --listening
nc -l 7000
# 客戶端連線命令,socat/nc 二選一
socat TCP:192.168.31.123:7000 -
nc 192.168.11.123 7000
UDP 協議的測試也非常類似,使用 netcat 的示例如下:
# 服務端,只監聽 ipv4
nc -u -l 8080
# 客戶端
nc -u 192.168.31.123 8080
# 客戶端本機測試,注意 localhost 會被優先解析為 ipv6! 這會導致服務端(ipv4)的 nc 接收不到資料!
nc -u localhost 8080
使用 socat 的 UDP 測試示例如下:
socat UDP-LISTEN:7000 -
socat UDP:192.168.31.123:7000 -
1.3 除錯 TLS 協議
參考 socat 官方文件:Securing Traffic Between two Socat Instances Using SSL
測試證照及私鑰的生成參見 [TLS 協議、TLS 證照、TLS 證照的配置方法、TLS 加密的破解手段]({{< ref "about-tls-cert/index.md" >}})
模擬一個 mTLS 伺服器,監聽 4433 埠,接收到的資料同樣輸出到 stdout:
# socat 需要使用同時包含證照和私鑰的 pem 檔案,生成方法如下
cat server.key server.crt > server.pem
cat client.key client.crt > client.pem
# 服務端啟動命令
socat openssl-listen:4433,reuseaddr,cert=server.pem,cafile=client.crt -
# 客戶端連線命令
socat - openssl-connect:192.168.31.123:4433,cert=client.pem,cafile=server.crt
# 或者使用 curl 連線(我們知道 ca.crt 和 server.crt 都能被用做 cacert/cafile)
curl -v --cacert ca.crt --cert client.crt --key client.key --tls-max 1.2 https://192.168.31.123:4433
上面的命令使用了 mTLS 雙向認證的協議,可通過設定 verify=0
來關掉客戶端認證,示例如下:
# socat 需要使用同時包含證照和私鑰的 pem 檔案,生成方法如下
cat server.key server.crt > server.pem
# 服務端啟動命令
socat openssl-listen:4433,reuseaddr,cert=server.pem,verify=0 -
# 客戶端連線命令,如果 ip/域名不受證照保護,就也需要新增 verify=0
socat - openssl-connect:192.168.31.123:4433,cafile=server.crt
# 或者使用 curl 連線,證照無效請新增 -k 跳過證照驗證
curl -v --cacert server.crt https://192.168.31.123:4433
2. 資料傳輸
通常傳輸檔案時,我都習慣使用 scp/ssh/rsync,但是 socat 其實也可以傳輸檔案。
以將 demo.tar.gz 從主機 A 傳送到主機 B 為例,
首先在資料傳送方 A 執行如下命令:
# -u 表示資料只從左邊的地址單向傳輸給右邊(socat 預設是一個雙向管道)
# -U 和 -u 相反,資料只從右邊單向傳輸給左邊
socat -u open:demo.tar.gz tcp-listen:2000,reuseaddr
然後在資料接收方 B 執行如下命令,就能把檔案接收到:
socat -u tcp:192.168.1.252:2000 open:demo.tar.gz,create
# 如果覺得太繁瑣,也可以直接通過 stdout 重定向
socat -u tcp:192.168.1.252:2000 - > demo.tar.gz
使用 netcat 也可以實現資料傳輸:
# 先在接收方啟動服務端
nc -l -p 8080 > demo.tar.gz
# 再在傳送方啟動客戶端傳送資料
nc 192.168.1.2 8080 < demo.tar.gz
3. 擔當臨時的 web 伺服器
使用 fork
reuseaddr
SYSTEM
三個命令,再用 systemd
/supervisor
管理一下,就可以用幾行命令實現一個簡單的後臺伺服器。
下面的命令將監聽 8080 埠,並將資料流和 web.py 的 stdio 連線起來,可以直接使用瀏覽器訪問 http://<ip>:8080
來檢視效果。
socat TCP-LISTEN:8080,reuseaddr,fork SYSTEM:"python3 web.py"
假設 web.py
的內容為:
print("hello world")
那 curl localhost:8080
就應該會輸出 hello world
4. 埠轉發
監聽 8080 埠,建立該埠與 baidu.com:80
之間的雙向管道:
socat TCP-LISTEN:8080,fork,reuseaddr TCP:baidu.com:80
拿 curl 命令測試一下,應該能正常訪問到百度:
# 注意指定 Host
curl -v -H 'Host: baidu.com' localhost:8080