首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Linux Netfilter 鉤子獲取源 MAC 地址:內核模塊開發指南

     編輯:程式設計綜合問答

核心問題

內核模塊加載後不生效 (不 DROP)、無法卸載、無法獲取源 MAC (ethhdr 結構體變更)。

現代內核 (3.10+) 獲取 MAC 正確姿勢

#include 
#include 
#include 
#include 

static unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
    if (!skb) return NF_ACCEPT;
    
    // skb_mac_header 已由網卡驅動設置 (接收路徑)
    // 發送路徑 (NF_INET_POST_ROUTING) 可能未推 MAC 頭,需 skb_push/skb_pull 處理
    struct ethhdr *eth = eth_hdr(skb); // 等價於 (struct ethhdr *)skb_mac_header(skb)
    if (!eth) return NF_ACCEPT;
    
    // 打印源 MAC
    printk(KERN_INFO "SRC MAC: %pM\n", eth->h_source); // %pM 內核格式化 MAC
    
    // 示例:僅允許特定 MAC
    u8 allowed_mac[6] = {0x11,0x22,0x33,0x44,0x55,0x66};
    if (ether_addr_equal(eth->h_source, allowed_mac))
        return NF_ACCEPT;
    return NF_DROP;
}

模塊加載不生效排查

  1. 鉤子優先級:NF_IP_PRI_FIRST 最高,但若有其他模塊 (如 docker/bridge) 同優先級順序不定。嘗試 NF_IP_PRI_FILTER - 1。
  2. 鉤子點選擇:NF_INET_POST_ROUTING 僅處理**本機發出**的包。若要攔截轉發包,用 NF_INET_FORWARD。
  3. 啟用調試:printk 確認 hook_func 被調用,檢查 dmesg。

模塊無法卸載 (rmmod 卡住)

  • **nf_unregister_hook 未返回** → 鉤子函數死循環/休眠/持有鎖。hook_func **不能睡眠**,不能調用 msleep/mutex_lock/copy_to_user 等。
  • 檢查 /proc/net/nf_conntrack、lsmod 確認引用計數。
  • 強制卸載:rmmod -f (不安全,可能導致內核崩潰)。

Makefile 規範寫法

obj-m := arp_fw.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

參考資源

避坑總結

  1. 用 eth_hdr(skb) 而非手動計算偏移。
  2. 鉤子函數**極簡、無睡眠、無鎖**、快速返回。
  3. 發送路徑 MAC 頭可能未構建,需在 NF_INET_LOCAL_OUT 或更早點處理,或用 dev_queue_xmit_nit 旁路獲取。
  4. 開發建議:先在 VM 內核調試 (kgdb/QEMU),再燒錄目標板。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved