Kernel module for monitoring packet routing information
开发一个Linux lkm
+ app program
,由app program
提供需要监控的源IP
地址,内核模块根据此IP
地址监控本机发送处与该源IP
地址相同的所有的packet
的5元组,源地址、目标地址、原端口、目标端口、协议,并将相关的信息传给应用程序,应用程序将该信息保存在文件中。
通信由用户程序发起,用户程序在开始时发送给内核模块一个源IP
地址,之后用户程序将进入监听状态,内核模块将该IP
地址以及用户程序的pid
存下来作为目标IP
地址和目标用户程序。之后用Netfilter
中钩子函数判断每一个从本机发出的数据包中的源IP
是否与目标IP
地址相同,如果相同则钩子程序将数据包中的路由信息保存下来,通过Netlink
发送给用户程序。用户程序接收到路由信息后,存在操作系统文件中。
内核版本:Linux5.0.-37
发行版本:Ubuntu 18.04.1
#查看系统日志
cat /var/log/kern.log
#打印系统日志到控制台
tail -f /var/log/kern.log &
#查看内核版本
cat /proc/version
#安装/卸载模块
insmod [mod]
rmmod [mod]
Linux
内核模块编程Netfilter
子系统与hook
函数编程struct sk_buff
,struct iphdr
,struct tcphdr
,struct udphdr
等网络相关结构体使用Netlink
通讯机制
在Linux4.13
之前,注册钩子使用的函数为:
nf_register_hook(reg);
高于Linux4.13
版本后,注册钩子使用的函数改变成了:
nf_register_net_hook(&init_net, reg);
若希望兼容Linux4.13
之前和之后的版本,可以这样写:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_register_net_hook(&init_net, reg)
#else
nf_register_hook(reg)
#endif
早期linux
内核中,Netfilter
的hook
函数原型为:
static unsigned int sample( unsigned int hooknum,
struct sk_buff * skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn) (struct sk_buff *));
但在高版本linux
内核(至少4.10以上已改变),Netfilter
的hook
函数原型变成了:
int sample_nf_hookfn(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state);
在较低版本linux
内核(Linux2.6)中,创建Netlink
处理函数使用:
//假设nl_data_ready为处理函数
nl_sk = netlink_kernel_create(&init_net,
NETLINK_TEST,
1,
nl_data_ready,
NULL,
HIS_MODULE);
高版本linux
内核(至少3.8.13以上已经改变)中,创建netlink
处理函数使用:
struct netlink_kernel_cfg cfg = {
.input = nl_data_ready,//该函数原型可参考内核代码,其他参数默认即可,可参考内核中的调用
};
nl_sk = netlink_kernel_create(&init_net,
NETLINK_TEST,
&cfg);
当执行完netlink_unicast
函数后skb
不需要内核模块去释放,也不能去释放,否则会导致崩溃。因为netlink_unicast
函数的返回不能保证用户层已经接受到消息,如果此时内核模块释放skb
,会导致用户程序接收到一个已经释放掉的消息,当内核尝试处理此消息时会导致崩溃。内核会处理skb
的释放,所以不会出现内存泄露问题, 这里给出了详细解释。
在封装发送到kernel
的消息时,我们需要依次对struct nlmsghdr
,struct iovec
,struct msghdr
进行封装。
内核模块和用户程序之间通讯与正常的使用socket
类似,还需要封装源地址和目的地址,但需要注意此处的地址本质上是进程pid
,而不是IP
地址。
getRoutingInfo.c: Makefile user.c
解决Linux4.13以上找不到nf_register_hook()函数的问题
Linux2.6下基于Netlink的用户空间与内核空间通信