Network / 網路連線測試 === ###### tags: `OS / Ubuntu / Network` ###### tags: `OS`, `Ubuntu`, `linux`, `command`, `network`, `curl`, `nc`, `netcat`, `printf`, `tcpdump`, `dns`, `nslookup` <br> [TOC] <br> ## curl ``` $ curl https://10.78.26.241:32779/version -k { "major": "1", "minor": "31", "gitVersion": "v1.31.7", "gitCommit": "da53587841b4960dc3bd2af1ec6101b57c79aff4", "gitTreeState": "clean", "buildDate": "2025-03-11T19:55:18Z", "goVersion": "go1.23.6", "compiler": "gc", "platform": "linux/amd64" } $ curl https://10.78.26.241:32779/version curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above. ``` - `-k`, `--insecure` Allow insecure server connections when using SSL ### 測試有無回應 ``` $ curl -I 185.125.190.81 HTTP/1.1 301 Moved Permanently Date: Wed, 16 Jul 2025 08:52:53 GMT Server: Apache/2.4.52 (Ubuntu) Location: http://www.ubuntu.com/usn/ Content-Type: text/html; charset=iso-8859-1 ``` - `-I, --head` (HTTP FTP FILE) Fetch the headers only! <br> ## nc - ### 全名 `nc` 是「netcat」的縮寫,netcat 是一個強大的網路工具,用來在 TCP 或 UDP 之間讀寫資料,常用於連線測試、連接埠掃描(大陸:端口掃描)、簡易的伺服器/客戶端模擬等用途。 - ### 安裝 ``` $ apt update & apt install -y netcat ``` - **troubleshooting** ``` ... Package netcat is a virtual package provided by: netcat-traditional 1.10-48 netcat-openbsd 1.226-1ubuntu2 You should explicitly select one to install ``` ```bash # netcat 只是個虛擬套件,Ubuntu 需要你選擇具體版本。 # 最常用且推薦的做法是選 netcat-openbsd: $ apt update & apt install -y netcat-openbsd ``` - ### 範例 ``` $ nc -vz www.google.com 80 Connection to www.google.com 80 port [tcp/http] succeeded! $ nc -vz 10.78.26.241 8080 Connection to 10.78.26.241 8080 port [tcp/http-alt] succeeded! ``` - `-v` Verbose - `-z` Zero-I/O mode [used for scanning] - 沒有 `-z` ``` $ nc -v 10.78.26.241 8080 Connection to 10.78.26.241 8080 port [tcp/http-alt] succeeded! HTTP/1.1 400 Bad Request content-type: text/plain; charset=utf-8 Connection: close Invalid HTTP request received. ``` - ### 為何出現 Invalid HTTP request received? 當你直接用 `nc -v 10.78.26.241 8080` 開一個 TCP 連線,卻沒有送出任何合法的 HTTP 請求(例如請求行、Host 標頭,最後還要以空行結束),伺服器的 HTTP 解析器就會回應 400 並顯示「Invalid HTTP request received」。換句話說,TCP 層連線成功了,但在應用層(HTTP)根本沒看到符合規範的請求訊息,所以才回你錯誤。 --- ### 正確範例 ```bash # 用 printf 將完整 HTTP/1.1 請求送給 nc printf 'GET / HTTP/1.1\r\nHost: 10.78.26.241\r\n\r\n' \ | nc 10.78.26.241 8080 ``` 以上會送出: ``` GET / HTTP/1.1 Host: 10.78.26.241 ``` (注意每行必須以 `\r\n` 結尾,最後還要一個空行告訴伺服器請求結束),這樣伺服器才會回傳正常的 200 OK 或其他有效回應。 --- ### 小結 - **400 Invalid HTTP request** = 伺服器已經收到 TCP 連線,但解析不到合法的 HTTP 請求。 - 使用 `nc` 測試時,必須**手動**輸入或管道送出符合 HTTP 規範的請求行、必要標頭(至少有 Host)及結尾空行。 - 否則就只是在「打開連線」卻沒「講 HTTP 語法」,伺服器自然回 400。 ### [測試] 實際回應結果 ``` HTTP/1.1 404 Not Found date: Thu, 08 May 2025 02:42:19 GMT server: uvicorn content-length: 22 content-type: application/json {"detail":"Not Found"} ``` <br> --- <br> ## Kubernetes 環境 > - 若你所有 pod 都不能 DNS,且 CoreDNS pod 是 Running,多半是網路、iptables、CNI 插件(如 flannel/cilium/calico)異常。 ### cmd: `nslookup` - 可看到 `nslookup` 自動補上 search domain - search domain 位於 `/etc/resolv.conf` ``` cat /etc/resolv.conf search slurm.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 ``` - resolver 會依 `/etc/resolv.conf`,自動補 search domain,嘗試查多種名稱,只要有一個有記錄就會回應;如果全沒,才回 `NXDOMAIN`。 ``` ** server can't find <domain>: NXDOMAIN ``` <br> ### image: busybox > - 用 BusyBox Pod 執行 > - `nslookup kubernetes.default` > - `curl https://kubernetes.default` > > 來測試存取 API Server ClusterIP (10.96.0.1:443) > - 疑慮: > - 經測試,好像要用 FQDN (Fully Qualified Domain Name ) 才能通? > - 好像不會去查 `/etc/resolv.conf` ```bash kubectl -n slurm run -it --rm busybox --image=busybox --restart=Never -- sh # 在 busybox 裡試: nslookup kubernetes.default # curl -k https://kubernetes.default ? nslookup slurm-controller nslookup slurm-controller.slurm.svc.cluster.local ``` - ### :warning: 經測試,若 DNS 無法通情況,請改用 `--image=infoblox/dnstools` 測試 > 可能原因:好像要用 FQDN (Fully Qualified Domain Name ) 才能通? - ### logs ``` / # curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090" -i sh: curl: not found / # nslookup monitor-kube-prometheus-st-prometheus.monitor Server: 10.96.0.10 Address: 10.96.0.10:53 ** server can't find monitor-kube-prometheus-st-prometheus.monitor: NXDOMAIN ** server can't find monitor-kube-prometheus-st-prometheus.monitor: NXDOMAIN / # cat /etc/resolv.conf search slurm.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 ``` - ### 透過 `--image=infoblox/dnstools` 則是正常 ``` $ kubectl -n slurm run -it --rm digtest --image=infoblox/dnstools dnstools# curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090" -i HTTP/1.1 302 Found Content-Type: text/html; charset=utf-8 Location: /query Date: Tue, 05 Aug 2025 04:22:11 GMT Content-Length: 29 <a href="/query">Found</a>. ``` - **`dnstools` 可能會去看 `/etc/resolv.conf` 設定** - **進到 `-n <namespace>` 的任意 pod,查看 `/etc/resolv.conf` 設定** ```conf $ cat /etc/resolv.conf search slurm.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 ``` - ### 測試 DNS 是否可解析(從 Pod 裡測) ``` # image: busybox:1.28 $ kubectl run dnsutils --rm -it --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default Server: 10.96.0.10 Address 1: 10.96.0.10 nslookup: can't resolve 'kubernetes.default' pod "dnsutils" deleted pod default/dnsutils terminated (Error) ``` ``` # image: busybox[:latest] $ kubectl run dnsutils --rm -it --image=busybox --restart=Never -- nslookup kubernetes.default nslookup: can't connect to remote host (10.96.0.10): Operation not permitted pod "dnsutils" deleted pod default/dnsutils terminated (Error) ``` - 發現奇怪的差異: - `busybox:1.28`:能跟 DNS server 建立連線(但查不到記錄)。 - `busybox:latest`:無法和 DNS server 建立連線,權限被阻擋(更嚴格的安全性限制,或網路設定問題)。 <br> ### image: infoblox/dnstools > 可使用指令:`dig`, `` - ### 測試 DNS 是否可解析(從 Pod 裡測) ```bash $ kubectl -n slurm run -it --rm dnstools --image=infoblox/dnstools --restart=Never # 在 busybox 裡試: nslookup kubernetes.default # curl -k https://kubernetes.default ? nslookup kubernetes.default.svc.cluster.local nslookup slurm-controller nslookup slurm-controller.slurm.svc.cluster.local nslookup monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local ``` - 再次進入 ``` $ kubectl -n slurm exec -it pod/digtest -- sh # 不支援 bash ``` <br> ### image: curlimage - ### 從一個「正常的 Pod」去測試能否連到 Kubernetes API Server 的 ClusterIP 10.96.0.1 ``` # 5glab $ kubectl run curltest --rm -it --image=curlimages/curl --restart=Never -- sh If you don't see a command prompt, try pressing enter. ~ $ curl -k https://10.96.0.1:443 { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"", "reason": "Forbidden", "details": {}, "code": 403 } ``` <br> ### node 上測試外部連線與 iptables SSH 到 node(如 stage-kube01),執行: ```bash curl -I https://1.1.1.1 curl -I https://8.8.8.8 nslookup google.com iptables -t nat -L -n ip route ``` <br> ### Pod 內測試外部連線 跑一個工具箱 pod: ```bash kubectl run -it --rm --restart=Never toolbox --image=ubuntu -- bash # 進去後 apt update apt install -y iputils-ping dnsutils curl ping 8.8.8.8 curl -I http://1.1.1.1 nslookup google.com ``` <br> ### [sidecar] ephemeral debug container (K8s 1.18+) (暫時性除錯容器) ```bash kubectl -n slurm debug -it slurm-controller-0 --image=ubuntu --target=slurmctld -- bash # 然後在 debug 容器內裝 ss/netstat/nc ``` - 指令結構說明 - `kubectl -n slurm debug` 使用 kubectl 的 debug 功能(指定 namespace 為 slurm)。 - `-it` 互動模式,加上 TTY。 - `slurm-controller-0` 要 debug 的目標 pod 名稱。 - `--image=ubuntu` 用哪個 image 來產生「暫時性的 debug 容器」(這邊用 ubuntu)。 - `--target=slurmctld` 指定這個 debug container 加掛進 pod 的哪個 container 的 namespace (會進入 slurmctld container 的 network/process 檔案系統等 namespace)。 - `-- bash` 啟動後直接給你 bash shell。 <br> --- --- <br> ## Linux 網路流量排查簡易教學 > ```bash > # from apt update > ping archive.ubuntu.com > curl http://archive.ubuntu.com > curl 91.189.91.82 > ``` ### 1. 確認封包會走哪個網卡 在多網卡或 VLAN 環境,**一定要先查流量會經過哪個介面**,否則 tcpdump 可能抓不到: ```bash ip route get <目標IP> ``` **範例:** ```bash ip route get 91.189.91.82 # 輸出:91.189.91.82 via 10.78.26.1 dev ens10f0.206 src 10.78.26.241 ... ``` 確認 `dev` 後面那個網卡就是要用來抓封包的介面。 --- ### 2. 正確啟動 tcpdump 抓封包 * 建議先開 tcpdump,再進行網路操作。 * 建議直接用 IP 過濾,這樣比較乾淨。 ```bash sudo tcpdump -i <interface> host <目標IP> ``` **範例:** ```bash sudo tcpdump -i ens10f0.206 host 91.189.91.82 ``` **如果懷疑走錯介面,可用** ```bash sudo tcpdump -i any host <目標IP> ``` --- ### 3. 執行你的網路操作 例如 curl: ```bash curl http://91.189.91.82 ``` 這時候 tcpdump 應該可以即時看到 SYN/ACK 或 HTTP GET/Response 的封包。 --- ### 4. 判讀 tcpdump 結果 * 看有沒有 SYN/ACK 來回(代表 TCP 三次握手成功) * 看 HTTP GET 及 HTTP 回應(如 200 OK、301 Moved Permanently 等) * 若完全沒封包,代表流量沒經過該介面,要重查路由。 * 若只看到單向 SYN,沒 ACK,可能是網路阻擋或防火牆問題。 --- ### 5. 常見錯誤與解法 * **抓錯 interface:** 用 `ip route get` 查正確介面。 * **tcpdump 太晚啟動:** 先開 tcpdump 再進行操作。 * **未過濾正確條件:** 用 `host <IP>` 過濾,或 `tcp port 80`。 * **SR-IOV、DPDK、VM特殊網路:** 某些特殊硬體網路 offload 流量,tcpdump 抓不到(需要針對 hypervisor、物理機抓封包)。 --- ### 6. 進階補充 * 如要同時觀察多個 IP,可用 `or`: ```bash sudo tcpdump -i <interface> host <IP1> or host <IP2> ``` * 要看所有 HTTP 流量: ```bash sudo tcpdump -i <interface> tcp port 80 ``` * 如果有 DNS 疑慮: ```bash sudo tcpdump -i <interface> port 53 ``` --- ### 小結 * **先確認路由,確定流量走哪個介面** * **再開 tcpdump 抓正確介面** * **再執行 curl 或 apt,觀察封包是否正常往返** * **遇到疑難雜症可用 `-i any` 嘗試** <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}