Network / iptables
===
###### tags: `OS / Ubuntu / Network`
###### tags: `OS`, `Ubuntu`, `linux`, `command`, `network`, `iptables`, `iptables NAT`
<br>
[TOC]
<br>
## `-t <table>`
| 表(table) | 作用 |
|-------------|------|
| **filter**(預設) | 做防火牆的過濾判斷(如 DROP/ACCEPT) |
| **nat** | 做 IP 位址轉換(如 SNAT, DNAT) |
| **mangle** | 修改封包欄位(TTL, TOS, 路徑等) |
| **raw** | 跳過連線追蹤(Connection Tracking) |
| **security** | SELinux 相關的存取控制 |
<br>
## iptables NAT 除錯教學(K8s: Flannel + Pod 無法出網)
> by gpt-4o (2025/06/05)
:::info
:bulb: [QuickStart] **啟用 iptables LOG,觀察封包經過哪裡**
```bash=
# 設置前先查看 monitor
sudo iptables -t nat -L POSTROUTING -v -n --line-numbers
# 設置 monitor
sudo iptables -t nat -I POSTROUTING 1 -j LOG --log-prefix "NAT-POST: "
# 查看 monitor
sudo iptables -t nat -L POSTROUTING -v -n --line-numbers
# 開 log 監聽
sudo journalctl -f | grep NAT-POST
# 發 request 測試,查看 log 有無 91.189.91.38
curl -I http://91.189.91.38
# 查看 monitor
sudo iptables -t nat -L POSTROUTING -v -n --line-numbers
# 移除 monitor
sudo iptables -t nat -D POSTROUTING 1
```
:::
### ✅ 一、觀察 NAT 規則
列出目前 NAT 表的 POSTROUTING 鏈(封包離開主機前的轉換規則):
```
sudo iptables -t nat -L POSTROUTING -v -n --line-numbers
```
常見欄位:
| 欄位 | 說明 |
|------|------|
| num | 規則編號 |
| pkts | 被這條規則匹配的封包數量 |
| target | MASQUERADE 表示 SNAT |
| source/destination | 對應來源與目的 IP 範圍 |
---
### ✅ 二、加入 MASQUERADE SNAT 規則(讓 Pod 封包能出網)
```
sudo iptables -t nat -I POSTROUTING 1 -s 10.244.0.0/16 ! -d 10.244.0.0/16 -j MASQUERADE
```
- **意義**:
- 在 `nat` 表中,
- 插入(Insert)一條規則到 `POSTROUTING` 鏈(處理封包出站前),
- 當來源是 Pod 網段(10.244.0.0/16),且目標不是 Pod 網段(! -d 10.244.0.0/16)時,
- 將來源 IP MASQUERADE(動態轉換為主機 IP)
- **參數**:
- `-t nat`
指的是要操作 **NAT(Network Address Translation)表**,這個表用來修改封包的來源或目的 IP,例如:
| 表(table) | 作用 |
|-------------|------|
| **filter**(預設) | 做防火牆的過濾判斷(如 DROP/ACCEPT) |
| **nat** | 做 IP 位址轉換(如 SNAT, DNAT) ✅ |
| **mangle** | 修改封包欄位(TTL, TOS, 路徑等) |
| **raw** | 跳過連線追蹤(Connection Tracking) |
| **security** | SELinux 相關的存取控制 |
- `-I 1`:插入到 POSTROUTING 鏈的第一條(優先匹配)
- `-s 10.244.0.0/16`:指定來源為 Pod IP(Flannel 預設)
- `! -d 10.244.0.0/16`:排除 Pod-to-Pod 內部流量
- `-j MASQUERADE`:動態 SNAT,轉換成 Node 的 IP 出站
- masquerade [͵mæskəˋred]
- n. 偽裝;化裝;欺騙
- vi. 化裝;冒充
---
### ✅ 三、插入 LOG 規則觀察封包是否進入 NAT
```
sudo iptables -t nat -I POSTROUTING 1 -j LOG --log-prefix "NAT-POST: "
```
> 📌 建議插入在第一條以觀察所有封包是否經過 POSTROUTING 鏈。
---
### ✅ 四、過濾 NAT 封包 log
系統 log 非常多,建議如下方式過濾出你要看的內容:
```
sudo journalctl -k -g 'NAT-POST'
```
或用 `tail`:
```
sudo tail -f /var/log/kern.log | grep 'NAT-POST'
```
範例輸出:
```
Jun 05 18:12:45 node kernel: NAT-POST: IN=cni0 OUT=eth0 SRC=10.244.0.3 DST=91.189.91.38 ...
```
你可以從中看到:
- `SRC=`:來源 IP,應是某個 Pod IP
- `DST=`:目標 IP(如 archive.ubuntu.com 的實際 IP)
---
### ✅ 五、如何從 Pod 發出測試封包?
使用 `curl` 搭配 IP(不經過 DNS):
```
kubectl exec -it ubuntu-2204-net-tools-pod -- curl -I http://91.189.91.38
```
或:
```
kubectl exec -it <pod-name> -- ping -c 2 91.189.91.38
```
> `91.189.91.38` 是 archive.ubuntu.com 的實體 IP,可用 `dig` 查出其他目標 IP
這些封包會觸發 `iptables` 的 POSTROUTING 鏈,若有成功觸發,`pkts/bytes` 會上升,`LOG` 也會輸出對應內容。
---
### ✅ 六、刪除指定規則
查出規則編號:
```
sudo iptables -t nat -L POSTROUTING --line-numbers -v -n
```
刪除(例如第 1 條):
```
sudo iptables -t nat -D POSTROUTING 1
```
---
### ✅ 七、檢查系統是否允許封包轉送(forward)
```
sysctl net.ipv4.ip_forward
# 應輸出:net.ipv4.ip_forward = 1
```
如為 0,請執行:
```
sudo sysctl -w net.ipv4.ip_forward=1
```
---
### ✅ 八、觀察封包是否真的從 Node 出去(tcpdump)
在 Node 執行:
```
sudo tcpdump -i any host 91.189.91.38
```
從 Pod 發出 curl 時觀察是否有封包經過,若沒有,表示:
- 封包卡在 Pod → bridge → Node 的某一環節
- 或沒有經過 SNAT,被網關擋掉
---
### ✅ 九、建議測試流程總結
1. 插入 LOG 規則觀察封包是否進入 POSTROUTING
2. 從 Pod 發出 curl 請求(用 IP,排除 DNS 問題)
3. 用 `journalctl -g 'NAT-POST'` 觀察 log 是否出現封包紀錄
4. 若 `pkts=0` 且 log 無紀錄 → 封包未進入 NAT(可能 bridge 或 route 問題)
---
以上為常用的 `iptables NAT` 除錯操作整理,特別適用於 Kubernetes Flannel CNI 中的 Pod 無法出網情境。
<br>
## 討論
### 解釋 `sudo iptables -D INPUT -j CILIUM_INPUT 2>/dev/null`
- ### Question
```
sudo iptables -D INPUT -j CILIUM_INPUT 2>/dev/null
```
這段指令怎麼解釋?
- ### GPT-4 Turbo (2025/06/16)
這段指令 `sudo iptables -D INPUT -j CILIUM_INPUT 2>/dev/null` 是用來在 Linux 系統中操作 **iptables** 防火牆規則的。讓我們來一步步解釋:
### 1. **`sudo`**:
* `sudo` 代表「SuperUser Do」,意思是以 **超級使用者(root)** 的身份執行後面的命令。這是因為操作防火牆通常需要更高的權限。
### 2. **`iptables`**:
* `iptables` 是一個用來設定和管理 Linux 防火牆的工具。它基於網路流量過濾規則,幫助管理進出系統的網路流量。
### 3. **`-D INPUT`**:
* `-D` 是 **刪除規則**(Delete)的意思,表示你要刪除一條現有的規則。
* `INPUT` 是指 **進來的網路流量**。因此,這條規則是針對處理進入系統的流量,且會刪除相關的規則。
### 4. **`-j CILIUM_INPUT`**:
* `-j` 代表「跳轉到(jump)」某個規則鏈。這意味著當流量進入該防火牆規則時,會轉到名為 `CILIUM_INPUT` 的自訂鏈(chain)進一步處理。
* `CILIUM_INPUT` 是某個特定的鏈名,這通常是在 **Cilium** 等網路管理工具中設置的規則鏈,用來進行流量管理、監控、或者處理。Cilium 是一個容器化環境下的網路和安全解決方案。
### 5. **`2>/dev/null`**:
* `2>` 是將 **標準錯誤輸出**(stderr)重定向到某個地方。
* `/dev/null` 是一個特殊設備,會丟棄所有寫入它的資料,這相當於「消聲處理」。換句話說,這一部分的作用是讓錯誤訊息不會顯示在終端機上,即便執行指令時出現錯誤也不會顯示出來。
### 綜合解釋:
這條命令的意思是:
* 以超級使用者身份執行 `iptables`。
* 刪除在 `INPUT` 鏈中,跳轉到 `CILIUM_INPUT` 鏈的規則。
* 如果有錯誤發生,將錯誤訊息丟到 `/dev/null`,也就是不顯示錯誤。
### 使用場景:
這條指令通常用來 **移除** 與 Cilium 相關的防火牆規則,尤其是在需要清理或調整 Cilium 的網路設定時,這樣做可以保證不再通過 `CILIUM_INPUT` 鏈處理進來的流量。
<br>
{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}