文章目录
Netfilter简介
Netfilter是从Linux 2.4开始引入内核的一个子系统,是在网络流程的若干位置放置了一些hook(钩子),将数据拉出来做一些处理(如包过滤,NAT等)后,再放回到网络流程。
与Spring的切面编程(AOP)相比:
- 虽然netfilter是面向过程语言编写的,但是其思想和AOP有相似之处,两者都是在某个流程中加了一道外来的流程,然后再返回原流程。
- AOP的主要目的是把与业务无关的关注点剥离(如日志、安全、事务)。
- Nerfilter会涉及到内核层的系统调用,AOP主要在用户层。
netfilter和iptables的关系
网络层的hook:
NF_IP_PRE_ROUTING:刚刚进入网络层的数据包
NF_IP_LOCAL_IN:经路由查找后,送往本机,INPUT包过滤
NF_IP_FORWARD:要转发的包,FORWORD包过滤
NF_IP_POST_ROUTING:要通过网络设备发出去的包
NF_IP_LOCAL_OUT:本机发出的包,OUTPUT包过滤
实验-target端
实验环境:ubuntu 18.04 kernel 4.15
源代码:nf_http.c getData.c Makefile
内核模块的操作
- 头文件 linux/kernel.h linux/module.h
- 初始化模块(netfilter,见下)
- 编译得到.ko文件
LKM的编译和应用层代码使用的gcc不同,它使用Makefile,kbuild。
make生成目标文件.ko,可以加载到内核。obj-m += hello-world.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
- 加载模块 sudo insmod nf_http.ko
- 打印10行信息 dmesg | tail
- 查看内核模块sudo lsmod
- 卸载模块 sudo rmmod nf_http (注意不用.ko)
完整的LKM编程模块
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
static int __init init_my_module(void) {
printk(KERN_INFO "Hello, Kernel!\n");
return 0;
}
static void __exit exit_my_module(void) {
printk(KERN_INFO "Bye, Kernel!\n");
}
module_init(init_my_module);
module_exit(exit_my_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("TEST");
初始化netfilter
- 头文件 :
- linux/netfilter.h
- linux/netfilter_ipv4.h
- 钩子点结构体
struct nf_hook_ops {
struct list_head list;
/* 此下的值由程序员填充 */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hook以升序的优先级排序 */
int priority;
};
- PRE_ROUTING 钩子:watch_in() 检查发出去的包
- POST_ROUTING钩子:watch_out() 检查收到的包
struct nf_hook_ops pre_hook;
struct nf_hook_ops post_hook;
int init_module()
{
pre_hook.hook = watch_in;
pre_hook.pf = PF_INET;
pre_hook.priority = NF_IP_PRI_FIRST;
pre_hook.hooknum = NF_INET_PRE_ROUTING;
post_hook.hook = watch_out;
post_hook.pf = PF_INET;
post_hook.priority = NF_IP_PRI_FIRST;
post_hook.hooknum = NF_INET_POST_ROUTING;
nf_register_net_hook(&init_net,&pre_hook);
nf_register_net_hook(&init_net,&post_hook);
return 0;
}
用netfilter过滤发出去的http包
static unsigned int watch_out(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct sk_buff *sb = skb;
struct tcphdr *tcp;
printk("post routing");
/* Make sure this is a TCP packet fir