Netfilter hook点概述
Netfilter全景图
二层hook示意图
三层hook示意图
hook调用示意图
Netfilter hook函数的应用场景
- 如果仅需判断报文是否经过了某个hook点,则采用【TCP/IP】【调试】丢包、流不通、错包等问题查证手段系列之二——防火墙这一节的方式即可,没有必要单独写钩子函数。
- 有时需要查看报文的内容,如需确认报文内容是否正确,或希望匹配特定报文做些动作(如截取dns报文、dhcp报文等),此时,可以考虑使用hook函数的方式。
具体开发过程
- 此处,仅以一个二层的hook点为例来说明。
Linux的module
- 编写一个Linux的module,可以编译为独立的ko,也可直接编入内核;
- 这部分可参考网上其他资料,类似下面的模式:
#ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #include <linux/module.h> #include <linux/kernel.h> static int __init pkt_process_init(void) { printk(KERN_ALERT "pkt_process_init called.\n"); return 0; } static void __exit pkt_process_exit(void) { printk(KERN_ALERT "pkt_process_exit called\n"); } module_init(pkt_process_init); module_exit(pkt_process_exit);
编写钩子函数
- 此处,可根据需要在br_pkt_hook_handle函数中,做一些报文的识别及处理工作。
static unsigned int br_pkt_hook_handle(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { struct ethhdr *eth; struct iphdr *iph; /* IPv4 header */ struct tcphdr *tcph; /* TCP header */ struct udph *udph; if (!skb) { return NF_ACCEPT; } eth = (struct ethhdr *) skb->data; iph = ip_hdr(skb); if (iph->protocol == IPPROTO_TCP) { tcph = tcp_hdr(skb); } else if (iph->protocol == IPPROTO_UDP) { udph= udp_hdr(skb); } /* other process */ }
注册钩子函数
static struct nf_hook_ops br_nf_ops_hooks[] = { { .hook = br_pkt_hook_handle, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_FORWARD, .priority = NF_BR_PRI_BRNF, }, }; static int __init pkt_process_init(void) { printk(KERN_ALERT "pkt_process_init called.\n"); for (i = 0; i < ARRAY_SIZE(br_nf_ops_hooks); i++) { if ((nf_register_hook(&br_nf_ops_hooks[i])) < 0) { printk("[%s:%d] nf_register_hook register failed!\n", __FUNCTION__, __LINE__); } } return 0; }
去注册钩子
static void __exit pkt_process_exit(void) { printk(KERN_ALERT "pkt_process_exit called\n"); for (i = 0; i < ARRAY_SIZE(br_nf_ops_hooks); i++) { if ((nf_unregister_hook(&br_nf_ops_hooks[i])) < 0) { printk("[%s:%d] nf_register_hook register failed!\n", __FUNCTION__, __LINE__); } } }