---
# System prepended metadata

title: Network / 網路連線測試
tags: [linux, OS, printf, command, network, dns, nc, netcat, tcpdump, curl, OS / Ubuntu / Network, Ubuntu, nslookup]

---

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