文章目录
ip_filter
功能简介
通过内核模块的方式向netfilter框架注册钩子函数,分析ip头部信息,提取源ip和目的ip,匹配到指定ip地址后进行过滤。
网络层
网络层引入了IP协议,制定了一套新地址,使得我们能够区分两台主机是否同属一个网络,这套地址就是网络地址,也就是所谓的IP地址。IP协议将这个32位的地址分为两部分,前面部分代表网络地址,后面部分表示该主机在局域网中的地址。如果两个IP地址在同一个子网内,则网络地址一定相同。为了判断IP地址中的网络地址,IP协议还引入了子网掩码,IP地址和子网掩码通过按位与运算后就可以得到网络地址。
通俗点讲,网络层就是以ip地址为唯一标识进行数据转发的,ip地址可以唯一标识一台主机。因此我们如果过滤局域网的ip地址,可以达到限制某台设备上网的效果,而如果过滤公网的ip地址,就可以限制所有设备访问特定资源的效果。
netfilter注册钩子函数
这里我们将hooknum设置为NF_INET_FORWARD
static struct nf_hook_ops ip_filter_ops[] __read_mostly = {
{
.hook = ip_filter_hook,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
};
static int __init ip_filter_init(void)
{
printk("ip filter...init\n");
nf_register_net_hooks(&init_net, ip_filter_ops, ARRAY_SIZE(ip_filter_ops));
return 0;
}
ip过滤钩子函数分析
源码
static u_int32_t ip_filter_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
struct udphdr *udph = NULL;
struct iphdr *iph = NULL;
int i;
char *black_ip_list[] = {
"192.168.66.167",
"8.8.8.8",
"114.114.114.114",
NULL
};
if (ct == NULL || !nf_ct_is_confirmed(ct))
{
return NF_ACCEPT;
}
iph = ip_hdr(skb);
if (!iph)
return NF_ACCEPT;
char src_ip[32] = {0};
char dst_ip[32] = {0};
sprintf(src_ip, "%pI4", &iph->saddr);
sprintf(dst_ip, "%pI4", &iph->daddr);
printk("src_ip = %s, dst_ip = %s\n", src_ip, dst_ip);
for (i = 0; black_ip_list[i] != NULL; i++)
{
if (0 == strcmp(src_ip, black_ip_list[i]) ||
0 == strcmp(dst_ip, black_ip_list[i]))
{
printk("drop ippacket %pI4--->%pI4\n", &iph->saddr, &iph->daddr);
return NF_DROP;
}
}
return NF_ACCEPT;
}
分析
源码中提取了ip头部的源ip和目的ip,并查询我们配置的过滤ip列表,匹配成功将返回NF_DROP进行丢包处理。
编译运行
参考前面章节
测试结果
root@OpenWrt:/fros#
root@OpenWrt:/fros# insmod ip_filter.ko
root@OpenWrt:/fros# <4>[52786.030458] ip filter...init
<4>[52797.584631] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52797.589199] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52798.585038] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52798.588543] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52799.585729] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52799.588981] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52800.586586] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52800.590504] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52816.371851] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52816.376783] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52817.373089] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52817.378449] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52818.373501] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52818.379103] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52819.374765] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52819.376784] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52820.376567] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52820.380384] drop ippacket 192.168.66.167--->39.156.69.79
作者简介
OpenWrt应用过滤插件作者(应用过滤用于控制app联网,可以过滤游戏、视频、聊天等几百款app)
从事嵌入式Linux开发近10年,主要负责路由器网通产品研发,精通OpenWrt系统,包括luci、消息机制、内核模块等。擅长模块:路由器上网行为管理、智能流控、上网认证、防火墙、虚拟服务器、多wan负载均衡等
开源作品地址:
https://github.com/destan19/OpenAppFilter
源码和文档
关注微信公众号可以获取更多技术文档、固件、源码等
微信扫码关注: