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 %}