NF_INET_PRE_ROUTING 掛鉤,攔截入站 IP 包ethhdr → iphdr → tcphdr,提取 MAC/IP/端口/proc/port,用戶態 cat /proc/port 讀取最新捕獲信息struct nf_hook_ops nfho; // Netfilter 掛鉤操作結構
struct proc_dir_entry *proc_file; // Procfs 入口
char *kbuf; // 內核緩衝區 (kmalloc)
int kbuf_len; // 有效數據長度
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)) {
struct sk_buff *sb = *skb;
struct ethhdr *eth = (struct ethhdr *)skb_mac_header(sb);
struct iphdr *iph = (struct iphdr *)skb_network_header(sb);
struct tcphdr *tcph = (struct tcphdr *)skb_transport_header(sb);
kbuf_len = 0;
if (ntohs(eth->h_proto) == ETH_P_IP && iph->protocol == IPPROTO_TCP) {
// 格式化輸出到內核緩衝區
kbuf_len += scnprintf(kbuf + kbuf_len, 1024 - kbuf_len,
"smac=%02x:%02x:%02x:%02x:%02x:%02x\n"
"dmac=%02x:%02x:%02x:%02x:%02x:%02x\n"
"sip=%pI4\n"
"dip=%pI4\n"
"sport=%d\n"
"dport=%d\n\n",
eth->h_source[0], eth->h_source[1], eth->h_source[2],
eth->h_source[3], eth->h_source[4], eth->h_source[5],
eth->h_dest[0], eth->h_dest[1], eth->h_dest[2],
eth->h_dest[3], eth->h_dest[4], eth->h_dest[5],
&iph->saddr, &iph->daddr,
ntohs(tcph->source), ntohs(tcph->dest));
}
return NF_ACCEPT; // 繼續正常協議棧處理
}
關鍵點:
skb_mac_header/skb_network_header/skb_transport_header 獲取各層頭指針,比手動偏移更安全。%pI4 內核專用格式化符,直接打印 __be32 IPv4 地址。scnprintf 防緩衝區溢出,返回寫入字節數。int proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data) {
if (off > 0) return 0; // 簡單實現:不支持分頁,off>0 返回 EOF
if (count < kbuf_len) return -EINVAL;
memcpy(buf, kbuf, kbuf_len);
return kbuf_len;
}
int init_module(void) {
kbuf = kmalloc(1024, GFP_KERNEL);
if (!kbuf) return -ENOMEM;
// 註冊 Netfilter Hook
nfho.hook = hook_func;
nfho.hooknum = NF_INET_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
// 創建 /proc/port
proc_file = create_proc_entry("port", 0644, NULL);
if (!proc_file) { nf_unregister_hook(&nfho); kfree(kbuf); return -ENOMEM; }
proc_file->read_proc = proc_read;
proc_file->owner = THIS_MODULE;
printk(KERN_INFO "netfilter_proc_module loaded\n");
return 0;
}
void cleanup_module(void) {
remove_proc_entry("port", NULL);
nf_unregister_hook(&nfho);
kfree(kbuf);
printk(KERN_INFO "netfilter_proc_module unloaded\n");
}
obj-m := netfilter_proc.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
make
sudo insmod netfilter_proc.ko
cat /proc/port # 查看捕獲信息
sudo rmmod netfilter_proc
dmesg | tail # 查看內核日誌
create_proc_entry 已棄用,改用 proc_create + proc_ops (或 file_operations)nf_hookfn 類型參數調整,參考 include/linux/netfilter.hseq_file 接口實現 Procfs 讀取,支持大數據分頁。