Linux netfilter 学习笔记 之十五 netfilter模块添加一个match
来源:互联网 发布:需要人陪 王力宏 知乎 编辑:程序博客网 时间:2024/06/16 09:57
分类: linux 网络 2014-07-24 21:11 1234人阅读 评论(0)收藏 举报
通过这段时间的学习,基本上熟悉了netfilter模块,为了进一步加深对netfilter的认识以及理解iptables与netfilter的联系,准备添加一个match模块。
在看到网关产品会有一个公网限制的功能,就想着添加一个公网数目限制的功能。
该模块实现的功能, 通过该match我们可以设置能够通过网关上网的数目,要想进行公网限制,就需要根据mac地址进行限制操作,这个模块放到ebtables里或许更好,或者在linux桥接模块里借助CAM表更容易实现。为了最小限度的修改协议栈的代码,放在netfilter里更好,由于对ebtables的研究不深入,即放在iptables里实现。
最后的命令如下:
# iptables -N access_limit
# iptables -I FORWARD -j access_limit
# iptables -A access_limit -i br0 -m maclimit --maclimit 1 --expire 30000 -j ACCEPT
其中 --maclimit 后面跟的数据是公网限制的数目, --expire后面跟的是超时时间(毫秒级),即对于一个已记录的mac,若在超时时间以后,没有收到相应的数据包,则删除该项。
1.相应的数据结构:
该数据结构为学习的mac地址表,当限制的数目不为0时,即对连接跟踪数据流进行学习,学习到一个mac地址,则将一个__xt_mac_limit_entry添加到xt_mac_limit_table->head链表中,当学习到的数目大于设置的数目后,则对后续学习到的mac数据,直接丢掉。
其中max_count代表限制的数目,mac_count代表当前已学习到的mac数目,gc_interval代表垃圾回收时间,也就是 --expire 后面的值。
typedef struct __xt_mac_limit_table
{
struct list_head head;
u_int32_t max_count;
u_int32_t mac_count;
spinlock_t lock;
u_int32_t gc_interval; /* gc interval */
bool init_flag;/*主要用于初始化*/
}xt_mac_limit_table;
该结构体对应于一个mac项,对于一个新的数据流,当学习到以后,则创建一个该结构的变量。其中list用于与xt_mac_limit_table->head进行链接,timeout定时器用于垃圾回收,即当网关在一定时间内没有再收到该mac地址相关的数据后,则释放该变量占用的内存,其中超时时间即为gc_interval,src_addr为源mac地址。
typedef struct __xt_mac_limit_entry
{
struct list_head list;
unsigned char src_addr[ETH_ALEN];
struct timer_list timeout;
}xt_mac_limit_entry;
/*tablesͨҲipt_entry_match->data[]ָ*/
typedef struct __xt_mac_limit_info
{
u_int32_t max_count;
u_int32_t expire;
}xt_mac_limit_info;
2. 功能实现
当maclimit为0时,则不进行公网接入限制,此时就不对数据包进行学习,全部允许通过。
当maclimit不为0时,则启动公网限制,对每一个数据流都进行mac学习,当学习到的mac超过限制后,则丢弃新的数据流。
而对于已学习到的mac,我们也要进行一个垃圾回收机制,即当在一定时间内收不到该mac相关的数据后,则删除该mac项,这就是所谓的垃圾回收,对于网络协议栈相关的功能开发,很多时候都要考虑到垃圾回收机制。
- 闲话少说,下面就是代码实现。
- Kernel:
- Linux3.X
- linux-3.x/net/netfilter/makefile:
- obj-m += xt_maclimit.o
- linux-3.x/net/netfilter/xt_maclimit.c
- #include <linux/netfilter/xt_maclimit.h>
- static xt_mac_limit_table *mac_list_table = NULL;
- static xt_mac_limit_entry *mac_limit_find_entry(unsigned char *macaddr)
- {
- xt_mac_limit_entry *pos, *n;
- if(macaddr == NULL)
- return NULL;
- list_for_each_entry_safe(pos, n,&mac_list_table->head, list)
- {
- if(memcmp(pos->src_addr, macaddr, ETH_ALEN) == 0)
- {
- return pos;
- }
- }
- return NULL;
- }
- static void mac_limit_delete_mac_entry(unsigned char *macaddr)
- {
- xt_mac_limit_entry *pos, *n;
- if(macaddr == NULL)
- return ;
- list_for_each_entry_safe(pos, n,&mac_list_table->head, list)
- {
- if(memcmp(pos->src_addr, macaddr, ETH_ALEN) == 0)
- {
- list_del(&pos->list);
- printk(KERN_INFO"%s: delete entry with mac addr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__,
- pos->src_addr[0], pos->src_addr[1], pos->src_addr[2], pos->src_addr[3], pos->src_addr[4], pos->src_addr[5]);
- kfree(pos);
- mac_list_table->mac_count--;
- return;
- }
- }
- }
- static void death_by_timeout(unsigned long mac_ent)
- {
- xt_mac_limit_entry *mac_entry = (xt_mac_limit_entry *)mac_ent;
- printk(KERN_INFO "%s: macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]
- ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],
- mac_entry->src_addr[5]);
- spin_lock(&mac_list_table->lock);
- if(!list_empty(&mac_list_table->head))
- {
- mac_limit_delete_mac_entry(mac_entry->src_addr);
- }
- spin_unlock(&mac_list_table->lock);
- }
- static xt_mac_limit_entry * mac_limit_create_entry(unsigned char *macaddr)
- {
- xt_mac_limit_entry *mac_entry;
- if((macaddr == NULL)||(mac_list_table->mac_count >= mac_list_table->max_count))
- return NULL;
- mac_entry = mac_limit_find_entry(macaddr);
- if(mac_entry)
- return mac_entry;
- mac_entry = kmalloc(sizeof(xt_mac_limit_entry), GFP_ATOMIC);
- if((mac_entry == NULL)||(mac_list_table->mac_count >= mac_list_table->max_count))
- {
- printk(KERN_INFO "%s: can not create new mac entry macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, macaddr[0]
- , macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
- return NULL;
- }
- memcpy(mac_entry->src_addr, macaddr, ETH_ALEN);
- init_timer(&mac_entry->timeout);
- mac_entry->timeout.data = (unsigned long)mac_entry;
- mac_entry->timeout.function = death_by_timeout;
- mac_entry->timeout.expires = jiffies + msecs_to_jiffies(mac_list_table->gc_interval);
- add_timer(&mac_entry->timeout);
- list_add(&mac_entry->list, &mac_list_table->head);
- mac_list_table->mac_count++;
- return mac_entry;
- }
- static bool mac_limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
- {
- bool ret;
- char mac_addr[ETH_ALEN];
- xt_mac_limit_entry *mac_entry;
- memset(mac_addr, 0, ETH_ALEN);
- if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER)
- return false;
- if (skb_mac_header(skb) < skb->head)
- return false;
- if (skb_mac_header(skb) + ETH_HLEN > skb->data)
- return false;
- spin_lock(&mac_list_table->lock);
- if(mac_list_table->max_count == 0)
- {
- printk(KERN_INFO"%s: NO LIMIT\n", __FUNCTION__);
- ret = true;
- }
- else
- {
- memcpy(mac_addr, eth_hdr(skb)->h_source, ETH_ALEN);
- mac_entry = mac_limit_find_entry(mac_addr);
- if(mac_entry == NULL)
- {
- if(mac_list_table->mac_count >= mac_list_table->max_count)
- {
- goto hotdrop;
- }
- else
- {
- mac_entry = mac_limit_create_entry(mac_addr);
- if(mac_entry == NULL)
- goto hotdrop;
- printk(KERN_INFO "%s: add entry success,macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]
- ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],
- mac_entry->src_addr[5]);
- ret = true;
- }
- }
- else
- {
- printk(KERN_INFO "%s: find entry , macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]
- ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],
- mac_entry->src_addr[5]);
- if(del_timer(&mac_entry->timeout))
- {
- printk("%s: update timeout expire\n", __FUNCTION__);
- mac_entry->timeout.expires = jiffies + msecs_to_jiffies(mac_list_table->gc_interval);
- add_timer(&mac_entry->timeout);
- }
- ret = true;
- }
- }
- spin_unlock(&mac_list_table->lock);
- return ret;
- hotdrop:
- spin_unlock(&mac_list_table->lock);
- printk(KERN_INFO "%s: drop packets\n", __FUNCTION__);
- par->hotdrop = true;
- return false;
- }
- static int mac_limit_checkentry(const struct xt_mtchk_param *par)
- {
- const xt_mac_limit_info *info = par->matchinfo;
- spin_lock(&mac_list_table->lock);
- if(mac_list_table->init_flag == false)
- {
- printk("%s: mac list table init\n", __FUNCTION__);
- mac_list_table->init_flag = true;
- INIT_LIST_HEAD(&mac_list_table->head);
- mac_list_table->max_count = info->max_count;
- mac_list_table->mac_count = 0;
- mac_list_table->gc_interval = info->expire;
- }
- printk(KERN_INFO"%s: max num is %d\n", __FUNCTION__, info->max_count);
- spin_unlock(&mac_list_table->lock);
- return 0;
- }
- static void mac_limit_destroy(const struct xt_mtdtor_param *par)
- {
- xt_mac_limit_entry *pos, *n;
- spin_lock(&mac_list_table->lock);
- printk(KERN_INFO"%s: destory mac list table\n", __FUNCTION__);
- if(mac_list_table->max_count != 0)
- {
- if(!list_empty(&mac_list_table->head))
- {
- list_for_each_entry_safe(pos, n,&mac_list_table->head, list)
- {
- if(timer_pending(&pos->timeout))
- del_timer(&pos->timeout);
- list_del(&pos->list);
- kfree(pos);
- }
- INIT_LIST_HEAD(&mac_list_table->head);
- }
- }
- mac_list_table->init_flag = false;
- spin_unlock(&mac_list_table->lock);
- }
- static struct xt_match mac_limit_mt_reg __read_mostly = {
- .name = "maclimit",
- .revision = 0,
- .family = NFPROTO_UNSPEC,
- .match = mac_limit_mt,
- .checkentry = mac_limit_checkentry,
- .destroy = mac_limit_destroy,
- .matchsize = sizeof(xt_mac_limit_info),
- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
- (1 << NF_INET_FORWARD),
- .me = THIS_MODULE,
- };
- static int __init mac_limit_mt_init(void)
- {
- mac_list_table = kmalloc(sizeof(xt_mac_limit_table),GFP_ATOMIC);
- spin_lock_init(&mac_list_table->lock);
- mac_list_table->init_flag = false;
- return xt_register_match(&mac_limit_mt_reg);
- }
- static void __exit mac_limit_mt_exit(void)
- {
- kfree(mac_list_table);
- xt_unregister_match(&mac_limit_mt_reg);
- }
- module_init(mac_limit_mt_init);
- module_exit(mac_limit_mt_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("jerry_chg");
- MODULE_DESCRIPTION("Xtables:access limit");
- MODULE_ALIAS("ipt_maclimit");
- include/linux/netfilter/xt_maclimit.h
- #ifndef _XT_MAC_LIMIT_H
- #define _XT_MAC_LIMIT_H
- #include <linux/module.h>
- #include <linux/if_arp.h>
- #include <linux/if_ether.h>
- #include <linux/etherdevice.h>
- #include <linux/netfilter_ipv4.h>
- #include <linux/netfilter_ipv6.h>
- #include <linux/netfilter/x_tables.h>
- #include <linux/spinlock.h>
- #include <linux/random.h>
- #include <linux/jhash.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
- #include <linux/proc_fs.h>
- #include <linux/seq_file.h>
- #include <linux/list.h>
- #include <linux/skbuff.h>
- #include <linux/mm.h>
- #include <linux/in.h>
- #include <linux/ip.h>
- #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
- #include <linux/ipv6.h>
- #include <net/ipv6.h>
- #endif
- #include <net/net_namespace.h>
- #include <net/netns/generic.h>
- #include <linux/netfilter_ipv4/ip_tables.h>
- #include <linux/netfilter_ipv6/ip6_tables.h>
- #include <linux/mutex.h>
- /*mac count limit table */
- typedef struct __xt_mac_limit_table
- {
- struct list_head head;
- u_int32_t max_count;
- u_int32_t mac_count;
- spinlock_t lock;
- u_int32_t gc_interval; /* gc interval */
- bool init_flag;
- }xt_mac_limit_table;
- /*for a mac struct*/
- typedef struct __xt_mac_limit_entry
- {
- struct list_head list;
- unsigned char src_addr[ETH_ALEN];
- struct timer_list timeout;
- }xt_mac_limit_entry;
- /*tablesͨҲipt_entry_match->data[]ָ*/
- typedef struct __xt_mac_limit_info
- {
- u_int32_t max_count;
- u_int32_t expire;
- }xt_mac_limit_info;
- #endif /*_XT_MAC_LIMIT_H*/
- Iptables下添加一个match还是比较简单的,代码如下:
- iptables-1.4.20/extensions/libxt_maclimit.c
- iptables-1.4.20/include/linux/netfilter/xt_maclimit.h
- xt_maclimit.h:
- #ifndef _XT_MAC_LIMIT_H
- #define _XT_MAC_LIMIT_H
- struct xt_maclimit_info {
- uint32_t limit_count;
- uint32_t expire;
- };
- #endif /*_XT_MAC_H*/
- libxt_maclimit.c:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdint.h>
- #include <xtables.h>
- #include <linux/netfilter/x_tables.h>
- #include <linux/netfilter/xt_maclimit.h>
- enum {
- O_MAC_LIMIT = 0,
- O_MAC_EXPIRE = 1,
- };
- static void maclimit_help(void)
- {
- printf(
- "mac match options:\n"
- "--maclimit max_count\n"
- "--expire after which time are idle entries expired?\n"
- " mac count limit module\n");
- }
- #define s struct xt_maclimit_info
- static const struct xt_option_entry maclimit_opts[] = {
- {.name = "maclimit", .id = O_MAC_LIMIT, .type = XTTYPE_UINT32,
- .flags = XTOPT_MAND | XTOPT_PUT,
- XTOPT_POINTER(s, limit_count)
- },
- {.name = "expire", .id = O_MAC_EXPIRE, .type = XTTYPE_UINT32,
- .flags = XTOPT_MAND | XTOPT_PUT,
- XTOPT_POINTER(s, expire)
- },
- XTOPT_TABLEEND,
- };
- #undef s
- static int maclimit_max_count_parse(const char *max, struct xt_maclimit_info *info)
- {
- uintmax_t v;
- char *end;
- if (!xtables_strtoul(max, &end, &v, 0, 0xffffffff))
- {
- xtables_error(PARAMETER_PROBLEM, "bad value for option "
- "\"--maclimit\", or out of range (0-32).");
- }
- return v;
- }
- static int maclimit_expire_parse(const char *expire, struct xt_maclimit_info *info)
- {
- uintmax_t v;
- char *end;
- if (!xtables_strtoul(expire, &end, &v, 0, 0xffffffff))
- {
- xtables_error(PARAMETER_PROBLEM, "bad value for option "
- "\"--maclimit\", or out of range (0-32).");
- }
- return v;
- }
- static void maclimit_parse(struct xt_option_call *cb)
- {
- struct xt_maclimit_info *maclimitinfo = cb->data;
- struct xt_option_entry *entry = cb->entry;
- xtables_option_parse(cb);
- switch(entry->id)
- {
- case O_MAC_LIMIT:
- maclimitinfo->limit_count = maclimit_max_count_parse(cb->arg, maclimitinfo);
- break;
- case O_MAC_EXPIRE:
- maclimitinfo->expire = maclimit_expire_parse(cb->arg, maclimitinfo);
- break;
- }
- printf("maclimit count is %d\n", maclimitinfo->limit_count);
- printf("expire is %d\n", maclimitinfo->expire);
- }
- static void print_maclimit(const uint32_t maclimit)
- {
- printf("mac limit count 0x%x", maclimit);
- }
- static void print_mac_expire(const uint32_t expire)
- {
- printf("mac entry expire 0x%x", expire);
- }
- static void
- maclimit_print(const void *ip, const struct xt_entry_match *match, int numeric)
- {
- const struct xt_maclimit_info *info = (void *)match->data;
- print_maclimit(info->limit_count);
- print_mac_expire(info->expire);
- }
- static void maclimit_save(const void *ip, const struct xt_entry_match *match)
- {
- const struct xt_maclimit_info *info = (void *)match->data;
- printf(" --maclimit");
- print_maclimit(info->limit_count);
- print_mac_expire(info->expire);
- }
- static struct xtables_match maclimit_match = {
- .family = NFPROTO_IPV4,
- .name = "maclimit",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_maclimit_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_maclimit_info)),
- .help = maclimit_help,
- .x6_parse = maclimit_parse,
- .print = maclimit_print,
- .save = maclimit_save,
- .x6_options = maclimit_opts,
- };
- void _init(void)
- {
- xtables_register_match(&maclimit_match);
- }
- 上文只是简单的实现了公网接入限制,没有在iptables中增加对ipv6的支持,仅仅在iptables中增加了对ipv4的支持,通过以上代码能够简单实现公网接入限制,这也加深了我对netfilter模块中增加match的认识。
- Linux netfilter 学习笔记 之十五 netfilter模块添加一个match
- Linux netfilter 学习笔记 之十五 netfilter模块添加一个match
- Linux netfilter 学习笔记 之三 ip层netfilter的table、rule、match、target结构分析
- Linux netfilter 学习笔记 之三 ip层netfilter的table、rule、match、target结构分析
- netfilter:开发一个match模块
- 学习笔记 之 linux netfilter
- Linux netfilter 学习笔记 之十 ip层netfilter的连接跟踪模块 学习小结
- Linux netfilter 学习笔记 之八 ip层netfilter的连接跟踪模块初始化
- Linux netfilter 学习笔记 之九 ip层netfilter的连接跟踪模块代码分析
- Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理
- Linux netfilter 学习笔记 之十二 ip层netfilter的NAT模块代码分析
- Linux netfilter 学习笔记 之十三 netfilter的SNAT模块是否支持UDP打洞
- Linux netfilter 学习笔记 之十四 netfilter模块会修改数据包关联的路由缓存吗
- Linux netfilter 学习笔记 之十二 ip层netfilter的NAT模块代码分析
- Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理
- Linux netfilter 学习笔记 之十三 netfilter的SNAT模块是否支持UDP打洞
- Linux netfilter 学习笔记 之八 ip层netfilter的连接跟踪模块初始化
- Linux netfilter 学习笔记 之九 ip层netfilter的连接跟踪模块代码分析
- DOM学习(JavaScript高级程序设计 第10章)
- springmvc+mybatis需要的jar包与详解
- 机器学习,斯坦福公开课
- 从生物进化浅谈产品创新
- Java基本类型和引用类型
- Linux netfilter 学习笔记 之十五 netfilter模块添加一个match
- What is SSAE 16, ISAE3402
- cf 17a Noldbach problem
- QT-利用C++仿制windown自带的记事本程序V1.0
- uva540
- Swift中ScrollView缩放图片的代理方法
- 字符串
- 自动跳转
- nyoj--860--又见01背包--01背包的变形