代码路径
git访问方式:https://gitee.com/yuewguo/url_filter.git
svn访问方式:svn://gitee.com/yuewguo/url_filter
一、自定义内核模块
static int UF_init(void) //安装模块入口
{
int ret = 0;
/* netfilter-hook */
ret = UF_NF_hook(); // 注册netfilter处理函数
if (0 != ret)
{
printk(KERN_EMERG"register hook fail!rn");
return ret;
}
/* syscall */
ret = UF_setsyscall();// 注册中断处理函数,用于接收用户态配置
UF_rule_init();// 初始化用户配置结构
printk(KERN_EMERG"install urlfilter succ!rn");
return 0;
}
static void UF_exit(void) //卸载模块入口
{
printk(KERN_EMERG"uninstall urlfilter succ!rn");
UF_NF_unhook();// 卸载注册netfilter处理函数
UF_resetsyscall();// 还原中断中断处理函数
UF_rule_exit();// 删除用户配置
return ;
}
module_init(UF_init);
module_exit(UF_exit);
二、Netfilter处理函数
netfilter处理框架如下图(转自网上):
需要注意的是,netfilter对外提供的hook点仅针对正向收包,应答报文不经过hook的业务点。
如果需要在应答流程中添加hook点需要自行修改netfilter代码。
struct nf_hook_ops UF_NF_hookfunc[] = {
{
.hook = UF_forward_entry,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = UF_forward_entry,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = UF_forward_entry,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = UF_forward_entry,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = UF_forward_entry,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
};
int UF_NF_hook(void) // 接上文
{
printk(KERN_EMERG"Register Netfilter Hookrn");
nf_register_hooks(UF_NF_hookfunc, ARRAY_SIZE(UF_NF_hookfunc)); // 注册netfilter处理函数
return 0;
}
UF_forward_entry
// 这块代码很简单,仅实现了简易的URL过滤功能,有兴趣可以自行补充其他功能。
三、命令行与内核交互
(1)内核部分
UF_setsyscall功能:改写系统223号中断,作为模块用户态和内核态的通信通道。
/* setup __NR_urlfilter 223*/
int UF_setsyscall(void)
{
entry = get_sys_call_table();
if (NULL == entry)
{
printk(KERN_EMERG"get_sys_call_table failrn");
return -1;
}
urlfilter_old = (unsigned long *)(entry[__NR_urlfilter]);
disable_write_protection();
entry[__NR_urlfilter] = (unsigned long *)UF_syscall; // 用户态触发223中断,UF_syscall会被执行
enable_write_protection();
return 0;
}
/* UF_syscall */
// 中断函数的入数个数可以自定义,用户态调用时保持一致即可。
// 需要注意的是,内核态和用户态的指针不能直接用,需要用copy_from_user和copy_to_user进行转换。
asmlinkage long UF_syscall(unsigned int optcode,
void *input, unsigned int inputlen,
void *output, unsigned int outputlen) //中断函数的入参
{
// ...
return ret;
}
(2)用户态部分
syscall(__NR_urlfilter, opt, input, inputlen, output, outputlen);
// __NR_urlfilter 为中断号
// opt, input, inputlen, output, outputlen 为中断函数的入参,见上文
2020.5.27 合肥