Linux 核心網路封包處理的靈魂是 Netfilter 框架。它在核心協定棧的五個關鍵點掛載 Hook,讓核心模組(如 iptables、nftables、連線追蹤、NAT)得以攔截、修改、裁決封包。本文從架構層面剖析 Netfilter 五大組件、五大 Hook 點、裁決回傳值、三大表(filter/nat/mangle)運作邏輯,並說明如何編寫核心模組掛載 Hook。
nf_hookfn)。封包流經 Hook 時,核心依優先順序調用所有已註冊的回呼,模組可檢查、修改、丟棄、佇列、重導封包。NF_QUEUE 的封包被移至使用者空間佇列(nfnetlink_queue),由用戶態程式(如 libnetfilter_queue 應用)非同步處理,處理完可重新注入核心同一 Hook 繼續流程。include/uapi/linux/netfilter_ipv4.h 定義):| Hook 常數 | 位置(核心路徑) | 典型應用 |
|---|---|---|
NF_IP_PRE_ROUTING (0) | 封包剛進入網路層,完成版本/校驗和檢查後 | DNAT(目的位址轉換)、透明代理、策略路由標記 |
NF_IP_LOCAL_IN (1) | 路由查詢後,確定送往本機 | INPUT 鏈過濾、本機服務存取控制 |
NF_IP_FORWARD (2) | 路由查詢後,確定需轉發 | FORWARD 鏈過濾、轉發封包 NAT |
NF_IP_POST_ROUTING (3) | 封包即將送出網路介面前 | SNAT(來源位址轉換)、MASQUERADE、封包標記輸出 |
NF_IP_LOCAL_OUT (4) | 本機進程產生的封包進入網路層前 | OUTPUT 鏈過濾、本機輸出 NAT、封包標記 |
| 值 | 語意 |
|---|---|
NF_ACCEPT | 繼續正常傳遞 |
NF_DROP | 悄悄丟棄,不回應發送端 |
NF_STOLEN | 模組接管封包,核心不再處理(如直接在核心回應 ICMP) |
NF_QUEUE | 送入使用者空間佇列待處理 |
NF_REPEAT | 重新調用同一 Hook(罕用,需極度小心避免迴圈) |
NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_LOCAL_OUT。每個封包只經過一個過濾點(優於 iptables 早期 ipchains 多次遍歷)。NF_IP_PRE_ROUTING (DNAT)、NF_IP_POST_ROUTING (SNAT)、NF_IP_LOCAL_OUT (本機輸出 DNAT)。只有連線第一個封包遍歷規則,後續封包依連線追蹤條目直接套用相同轉換。NF_IP_PRE_ROUTING、NF_IP_LOCAL_OUT。支援修改 TOS/DSCP、設定 skb->mark(供 tc/ip rule 策略路由使用)。#include
#include
#include
#include
#include
static struct nf_hook_ops nfho = {
.hook = my_hook_fn,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST, // 最高優先級
};
unsigned int my_hook_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph = ip_hdr(skb);
if (!iph || iph->protocol != IPPROTO_TCP) return NF_ACCEPT;
struct tcphdr *tcph = tcp_hdr(skb);
if (tcph->dest == htons(80)) {
printk(KERN_INFO "HTTP request to %pI4:%d\n", &iph->daddr, ntohs(tcph->dest));
// 可在此修改封包、丟棄、標記
}
return NF_ACCEPT;
}
static int __init my_init(void) {
return nf_register_net_hook(&init_net, &nfho);
}
static void __exit my_exit(void) {
nf_unregister_net_hook(&init_net, &nfho);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
關鍵結構體欄位:
- list:初始化為 {NULL, NULL}。
- pf:協定族(PF_INET IPv4)。
- hooknum:Hook 號(0~4)。
- priority:優先級,數值越小越早執行。參考 netfilter_ipv4.h 內建優先級列舉(NF_IP_PRI_FIRST、NF_IP_PRI_CONNTRACK、NF_IP_PRI_MANGLE、NF_IP_PRI_NAT_DST、NF_IP_PRI_FILTER、NF_IP_PRI_NAT_SRC、NF_IP_PRI_LAST)。
nftables(Linux 3.13+)取代 iptables/ip6tables/arptables/ebtables,提供單一 CLI(nft)、統一核心 API(nf_tables)、原生支援集合/字典/遞迴集合、原子式規則更新、JSON 輸出。底層仍複用 Netfilter 相同 5 大 Hook,但規則評估引擎改為虛擬機器(nft_expr),效能與擴充性大幅提升。
Netfilter 以「Hook + 註冊回呼 + 裁決值」極簡抽象,支撐起 Linux 整個封包處理生態。理解五大 Hook 語意、三大表掛載點、優先級排序,是進階網路除錯、開發核心模組、設計高效能防火牆規則的基石。