Linux netfilter 学习笔记 之十五 netfilter模块添加一个match

来源:互联网 发布:需要人陪 王力宏 知乎 编辑:程序博客网 时间:2024/06/16 09:57


分类: linux 网络 1234人阅读 评论(0)收藏 举报    

通过这段时间的学习,基本上熟悉了netfilter模块,为了进一步加深对netfilter的认识以及理解iptablesnetfilter的联系,准备添加一个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_intervalsrc_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. 功能实现

maclimit0时,则不进行公网接入限制,此时就不对数据包进行学习,全部允许通过。

maclimit不为0时,则启动公网限制,对每一个数据流都进行mac学习,当学习到的mac超过限制后,则丢弃新的数据流。

 而对于已学习到的mac,我们也要进行一个垃圾回收机制,即当在一定时间内收不到该mac相关的数据后,则删除该mac项,这就是所谓的垃圾回收,对于网络协议栈相关的功能开发,很多时候都要考虑到垃圾回收机制。

 












[cpp] view plaincopyprint?
  1. 闲话少说,下面就是代码实现。  
  2. Kernel:  
  3. Linux3.X  
  4. linux-3.x/net/netfilter/makefile:  
  5. obj-m += xt_maclimit.o  
  6.   
  7.   
  8.   
  9. linux-3.x/net/netfilter/xt_maclimit.c  
  10. #include <linux/netfilter/xt_maclimit.h>  
  11.   
  12. static xt_mac_limit_table *mac_list_table = NULL;  
  13.   
  14. static xt_mac_limit_entry *mac_limit_find_entry(unsigned char *macaddr)  
  15. {  
  16.     xt_mac_limit_entry *pos, *n;  
  17.   
  18.     if(macaddr == NULL)  
  19.         return NULL;  
  20.       
  21.     list_for_each_entry_safe(pos, n,&mac_list_table->head, list)  
  22.     {  
  23.         if(memcmp(pos->src_addr, macaddr, ETH_ALEN) == 0)  
  24.         {  
  25.             return pos;  
  26.         }  
  27.     }  
  28.       
  29.     return NULL;  
  30. }  
  31.   
  32. static void mac_limit_delete_mac_entry(unsigned char *macaddr)  
  33. {  
  34.   
  35.     xt_mac_limit_entry *pos, *n;  
  36.   
  37.     if(macaddr == NULL)  
  38.         return ;  
  39.   
  40.     list_for_each_entry_safe(pos, n,&mac_list_table->head, list)  
  41.     {  
  42.         if(memcmp(pos->src_addr, macaddr, ETH_ALEN) == 0)  
  43.         {  
  44.             list_del(&pos->list);  
  45.             printk(KERN_INFO"%s: delete entry with mac addr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__,  
  46.             pos->src_addr[0], pos->src_addr[1], pos->src_addr[2], pos->src_addr[3], pos->src_addr[4], pos->src_addr[5]);  
  47.             kfree(pos);  
  48.             mac_list_table->mac_count--;  
  49.               
  50.             return;  
  51.         }  
  52.     }  
  53.   
  54.   
  55. }  
  56. static void death_by_timeout(unsigned long mac_ent)  
  57. {  
  58.     xt_mac_limit_entry *mac_entry = (xt_mac_limit_entry *)mac_ent;  
  59.   
  60.     printk(KERN_INFO "%s: macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]  
  61.         ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],  
  62.         mac_entry->src_addr[5]);  
  63.       
  64.     spin_lock(&mac_list_table->lock);  
  65.     if(!list_empty(&mac_list_table->head))  
  66.     {  
  67.         mac_limit_delete_mac_entry(mac_entry->src_addr);  
  68.     }  
  69.     spin_unlock(&mac_list_table->lock);  
  70. }  
  71.   
  72. static xt_mac_limit_entry * mac_limit_create_entry(unsigned char *macaddr)  
  73. {  
  74.     xt_mac_limit_entry *mac_entry;  
  75.   
  76.     if((macaddr == NULL)||(mac_list_table->mac_count >= mac_list_table->max_count))  
  77.         return NULL;  
  78.   
  79.     mac_entry = mac_limit_find_entry(macaddr);  
  80.     if(mac_entry)  
  81.         return mac_entry;  
  82.   
  83.     mac_entry = kmalloc(sizeof(xt_mac_limit_entry), GFP_ATOMIC);  
  84.     if((mac_entry == NULL)||(mac_list_table->mac_count >= mac_list_table->max_count))  
  85.     {  
  86.         printk(KERN_INFO "%s: can not create new mac entry macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, macaddr[0]  
  87.             , macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);  
  88.           
  89.         return NULL;  
  90.     }  
  91.       
  92.     memcpy(mac_entry->src_addr, macaddr, ETH_ALEN);  
  93.     init_timer(&mac_entry->timeout);  
  94.     mac_entry->timeout.data = (unsigned long)mac_entry;  
  95.     mac_entry->timeout.function = death_by_timeout;  
  96.     mac_entry->timeout.expires = jiffies + msecs_to_jiffies(mac_list_table->gc_interval);  
  97.     add_timer(&mac_entry->timeout);  
  98.     list_add(&mac_entry->list, &mac_list_table->head);  
  99.     mac_list_table->mac_count++;   
  100.       
  101.     return mac_entry;  
  102.   
  103.       
  104. }  
  105. static bool mac_limit_mt(const struct sk_buff *skb, struct xt_action_param *par)  
  106. {  
  107.     bool ret;  
  108.     char mac_addr[ETH_ALEN];  
  109.     xt_mac_limit_entry *mac_entry;  
  110.   
  111.     memset(mac_addr, 0, ETH_ALEN);  
  112.   
  113.     if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER)  
  114.         return false;  
  115.     if (skb_mac_header(skb) < skb->head)  
  116.         return false;  
  117.     if (skb_mac_header(skb) + ETH_HLEN > skb->data)  
  118.         return false;  
  119.       
  120.     spin_lock(&mac_list_table->lock);  
  121.       
  122.     if(mac_list_table->max_count == 0)  
  123.     {  
  124.         printk(KERN_INFO"%s: NO LIMIT\n", __FUNCTION__);  
  125.         ret = true;  
  126.     }  
  127.     else  
  128.     {  
  129.         memcpy(mac_addr, eth_hdr(skb)->h_source, ETH_ALEN);  
  130.         mac_entry = mac_limit_find_entry(mac_addr);  
  131.         if(mac_entry == NULL)  
  132.         {  
  133.             if(mac_list_table->mac_count >= mac_list_table->max_count)  
  134.             {  
  135.                 goto hotdrop;  
  136.             }  
  137.             else  
  138.             {  
  139.                 mac_entry = mac_limit_create_entry(mac_addr);  
  140.                 if(mac_entry == NULL)  
  141.                     goto hotdrop;  
  142.                   
  143.                 printk(KERN_INFO "%s: add entry success,macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]  
  144.                     ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],  
  145.                     mac_entry->src_addr[5]);  
  146.                 ret = true;  
  147.             }  
  148.         }  
  149.         else  
  150.         {  
  151.             printk(KERN_INFO "%s: find entry , macaddr is %x:%x:%x:%x:%x:%x\n", __FUNCTION__, mac_entry->src_addr[0]  
  152.                     ,mac_entry->src_addr[1], mac_entry->src_addr[2], mac_entry->src_addr[3], mac_entry->src_addr[4],  
  153.                     mac_entry->src_addr[5]);  
  154.             if(del_timer(&mac_entry->timeout))  
  155.             {  
  156.                 printk("%s: update timeout expire\n", __FUNCTION__);  
  157.                 mac_entry->timeout.expires = jiffies + msecs_to_jiffies(mac_list_table->gc_interval);  
  158.                 add_timer(&mac_entry->timeout);  
  159.             }  
  160.             ret = true;  
  161.         }  
  162.     }  
  163.   
  164.     spin_unlock(&mac_list_table->lock);  
  165.     return ret;  
  166.   
  167. hotdrop:   
  168.      spin_unlock(&mac_list_table->lock);  
  169.      printk(KERN_INFO "%s: drop packets\n", __FUNCTION__);  
  170.     par->hotdrop = true;  
  171.     return false;     
  172. }  
  173. static int mac_limit_checkentry(const struct xt_mtchk_param *par)  
  174. {  
  175.     const  xt_mac_limit_info *info = par->matchinfo;  
  176.   
  177.     spin_lock(&mac_list_table->lock);  
  178.     if(mac_list_table->init_flag == false)  
  179.     {  
  180.         printk("%s: mac list table init\n", __FUNCTION__);  
  181.         mac_list_table->init_flag = true;  
  182.         INIT_LIST_HEAD(&mac_list_table->head);  
  183.         mac_list_table->max_count = info->max_count;  
  184.         mac_list_table->mac_count = 0;  
  185.         mac_list_table->gc_interval = info->expire;  
  186.     }  
  187.   
  188.     printk(KERN_INFO"%s: max num is %d\n", __FUNCTION__, info->max_count);  
  189.   
  190.     spin_unlock(&mac_list_table->lock);  
  191.   
  192.     return 0;  
  193. }  
  194.   
  195. static void mac_limit_destroy(const struct xt_mtdtor_param *par)  
  196. {  
  197.     xt_mac_limit_entry *pos, *n;  
  198.   
  199.   
  200.     spin_lock(&mac_list_table->lock);  
  201.   
  202.     printk(KERN_INFO"%s: destory mac list table\n", __FUNCTION__);  
  203.     if(mac_list_table->max_count != 0)  
  204.     {  
  205.         if(!list_empty(&mac_list_table->head))  
  206.         {  
  207.             list_for_each_entry_safe(pos, n,&mac_list_table->head, list)  
  208.             {     
  209.                 if(timer_pending(&pos->timeout))  
  210.                     del_timer(&pos->timeout);  
  211.                       
  212.                 list_del(&pos->list);  
  213.                 kfree(pos);  
  214.             }  
  215.             INIT_LIST_HEAD(&mac_list_table->head);  
  216.         }  
  217.           
  218.     }  
  219.     mac_list_table->init_flag = false;  
  220.     spin_unlock(&mac_list_table->lock);  
  221. }  
  222. static struct xt_match mac_limit_mt_reg __read_mostly = {  
  223.     .name      = "maclimit",  
  224.     .revision  = 0,  
  225.     .family    = NFPROTO_UNSPEC,  
  226.     .match     = mac_limit_mt,  
  227.     .checkentry = mac_limit_checkentry,  
  228.     .destroy = mac_limit_destroy,  
  229.     .matchsize = sizeof(xt_mac_limit_info),  
  230.     .hooks     = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |  
  231.                  (1 << NF_INET_FORWARD),  
  232.     .me        = THIS_MODULE,  
  233. };  
  234. static int __init mac_limit_mt_init(void)  
  235. {  
  236.     mac_list_table = kmalloc(sizeof(xt_mac_limit_table),GFP_ATOMIC);  
  237.     spin_lock_init(&mac_list_table->lock);  
  238.     mac_list_table->init_flag = false;  
  239.     return xt_register_match(&mac_limit_mt_reg);  
  240. }  
  241.   
  242. static void __exit mac_limit_mt_exit(void)  
  243. {  
  244.     kfree(mac_list_table);  
  245.     xt_unregister_match(&mac_limit_mt_reg);  
  246. }  
  247.   
  248. module_init(mac_limit_mt_init);  
  249. module_exit(mac_limit_mt_exit);  
  250. MODULE_LICENSE("GPL");  
  251. MODULE_AUTHOR("jerry_chg");  
  252. MODULE_DESCRIPTION("Xtables:access limit");  
  253. MODULE_ALIAS("ipt_maclimit");  
  254.   
  255.   
  256.   
  257.   
  258.  include/linux/netfilter/xt_maclimit.h  
  259. #ifndef _XT_MAC_LIMIT_H  
  260. #define _XT_MAC_LIMIT_H  
  261. #include <linux/module.h>  
  262. #include <linux/if_arp.h>  
  263. #include <linux/if_ether.h>  
  264. #include <linux/etherdevice.h>  
  265. #include <linux/netfilter_ipv4.h>  
  266. #include <linux/netfilter_ipv6.h>  
  267. #include <linux/netfilter/x_tables.h>  
  268. #include <linux/spinlock.h>  
  269. #include <linux/random.h>  
  270. #include <linux/jhash.h>  
  271. #include <linux/slab.h>  
  272. #include <linux/vmalloc.h>  
  273. #include <linux/proc_fs.h>  
  274. #include <linux/seq_file.h>  
  275. #include <linux/list.h>  
  276.   
  277. #include <linux/skbuff.h>  
  278. #include <linux/mm.h>  
  279. #include <linux/in.h>  
  280. #include <linux/ip.h>  
  281. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)  
  282. #include <linux/ipv6.h>  
  283. #include <net/ipv6.h>  
  284. #endif  
  285.   
  286. #include <net/net_namespace.h>  
  287. #include <net/netns/generic.h>  
  288.   
  289. #include <linux/netfilter_ipv4/ip_tables.h>  
  290. #include <linux/netfilter_ipv6/ip6_tables.h>  
  291. #include <linux/mutex.h>  
  292.   
  293. /*mac count limit table */  
  294. typedef struct __xt_mac_limit_table  
  295. {  
  296.         struct list_head head;  
  297.         u_int32_t max_count;  
  298.         u_int32_t mac_count;  
  299.         spinlock_t lock;  
  300.         u_int32_t gc_interval;  /* gc interval */  
  301.         bool init_flag;  
  302. }xt_mac_limit_table;  
  303.   
  304. /*for a  mac struct*/  
  305. typedef struct __xt_mac_limit_entry  
  306. {  
  307.         struct list_head list;  
  308.     unsigned char src_addr[ETH_ALEN];  
  309.         struct timer_list timeout;  
  310. }xt_mac_limit_entry;  
  311.   
  312. /*tablesͨҲipt_entry_match->data[]ָ*/  
  313. typedef struct __xt_mac_limit_info  
  314. {  
  315.         u_int32_t max_count;  
  316.         u_int32_t expire;  
  317. }xt_mac_limit_info;  
  318.   
  319. #endif /*_XT_MAC_LIMIT_H*/  
  320.   
  321.   
  322.   
  323.   
  324.   
  325.   
  326. Iptables下添加一个match还是比较简单的,代码如下:  
  327.   
  328. iptables-1.4.20/extensions/libxt_maclimit.c  
  329. iptables-1.4.20/include/linux/netfilter/xt_maclimit.h  
  330.   
  331.   
  332. xt_maclimit.h:  
  333.   
  334. #ifndef _XT_MAC_LIMIT_H  
  335. #define _XT_MAC_LIMIT_H  
  336.   
  337. struct xt_maclimit_info {  
  338.     uint32_t limit_count;  
  339.         uint32_t expire;  
  340. };  
  341. #endif /*_XT_MAC_H*/  
  342.   
  343.   
  344. libxt_maclimit.c:  
  345. #include <stdio.h>  
  346. #include <stdlib.h>  
  347. #include <string.h>  
  348. #include <stdint.h>  
  349. #include <xtables.h>  
  350. #include <linux/netfilter/x_tables.h>  
  351. #include <linux/netfilter/xt_maclimit.h>  
  352.   
  353. enum {  
  354.         O_MAC_LIMIT = 0,  
  355.         O_MAC_EXPIRE = 1,  
  356. };  
  357.   
  358. static void maclimit_help(void)  
  359. {  
  360.         printf(  
  361. "mac match options:\n"  
  362. "--maclimit max_count\n"  
  363. "--expire  after which time are idle entries expired?\n"  
  364. "                               mac count limit module\n");  
  365. }  
  366.   
  367. #define s struct xt_maclimit_info  
  368. static const struct xt_option_entry maclimit_opts[] = {  
  369.         {.name = "maclimit", .id = O_MAC_LIMIT, .type = XTTYPE_UINT32,  
  370.                 .flags = XTOPT_MAND | XTOPT_PUT,  
  371.                 XTOPT_POINTER(s, limit_count)  
  372.         },  
  373.         {.name = "expire", .id = O_MAC_EXPIRE, .type = XTTYPE_UINT32,  
  374.                 .flags = XTOPT_MAND | XTOPT_PUT,  
  375.                  XTOPT_POINTER(s, expire)  
  376.         },  
  377.         XTOPT_TABLEEND,  
  378. };  
  379. #undef s  
  380.   
  381.   
  382.   
  383.   
  384.   
  385. static int  maclimit_max_count_parse(const char *max, struct xt_maclimit_info *info)  
  386. {  
  387.         uintmax_t v;  
  388.         char *end;  
  389.   
  390.         if (!xtables_strtoul(max, &end, &v, 0, 0xffffffff))  
  391.         {  
  392.                 xtables_error(PARAMETER_PROBLEM, "bad value for option "  
  393.                         "\"--maclimit\", or out of range (0-32).");  
  394.         }  
  395.   
  396.         return v;  
  397. }  
  398.   
  399.   
  400. static int  maclimit_expire_parse(const char *expire, struct xt_maclimit_info *info)  
  401. {  
  402.         uintmax_t v;  
  403.         char *end;  
  404.   
  405.         if (!xtables_strtoul(expire, &end, &v, 0, 0xffffffff))  
  406.         {  
  407.                 xtables_error(PARAMETER_PROBLEM, "bad value for option "  
  408.                         "\"--maclimit\", or out of range (0-32).");  
  409.         }  
  410.   
  411.         return v;  
  412. }  
  413.   
  414. static void maclimit_parse(struct xt_option_call *cb)  
  415. {  
  416.         struct xt_maclimit_info *maclimitinfo = cb->data;  
  417.         struct xt_option_entry *entry = cb->entry;  
  418.   
  419.         xtables_option_parse(cb);  
  420.         switch(entry->id)  
  421.         {  
  422.                 case O_MAC_LIMIT:  
  423.                         maclimitinfo->limit_count = maclimit_max_count_parse(cb->arg, maclimitinfo);  
  424.                         break;  
  425.   
  426.                 case O_MAC_EXPIRE:  
  427.                         maclimitinfo->expire = maclimit_expire_parse(cb->arg, maclimitinfo);  
  428.                         break;  
  429.         }  
  430.   
  431.         printf("maclimit count is %d\n", maclimitinfo->limit_count);  
  432.         printf("expire is %d\n", maclimitinfo->expire);  
  433.   
  434. }  
  435.   
  436. static void print_maclimit(const uint32_t maclimit)  
  437. {  
  438.         printf("mac limit count 0x%x", maclimit);  
  439. }  
  440. static void print_mac_expire(const uint32_t expire)  
  441. {  
  442.         printf("mac entry expire 0x%x", expire);  
  443. }  
  444. static void  
  445. maclimit_print(const void *ip, const struct xt_entry_match *match, int numeric)  
  446. {  
  447.         const struct xt_maclimit_info *info = (void *)match->data;  
  448.   
  449.         print_maclimit(info->limit_count);  
  450.         print_mac_expire(info->expire);  
  451. }  
  452.   
  453. static void maclimit_save(const void *ip, const struct xt_entry_match *match)  
  454. {  
  455.         const struct xt_maclimit_info *info = (void *)match->data;  
  456.   
  457.         printf(" --maclimit");  
  458.         print_maclimit(info->limit_count);  
  459.         print_mac_expire(info->expire);  
  460. }  
  461.   
  462. static struct xtables_match maclimit_match = {  
  463.         .family         = NFPROTO_IPV4,  
  464.         .name           = "maclimit",  
  465.         .version        = XTABLES_VERSION,  
  466.         .size           = XT_ALIGN(sizeof(struct xt_maclimit_info)),  
  467.         .userspacesize  = XT_ALIGN(sizeof(struct xt_maclimit_info)),  
  468.         .help           = maclimit_help,  
  469.         .x6_parse       = maclimit_parse,  
  470.         .print          = maclimit_print,  
  471.         .save           = maclimit_save,  
  472.         .x6_options     = maclimit_opts,  
  473. };  
  474.   
  475. void _init(void)  
  476. {  
  477.         xtables_register_match(&maclimit_match);  
  478. }  

[cpp] view plaincopyprint?
  1. 上文只是简单的实现了公网接入限制,没有在iptables中增加对ipv6的支持,仅仅在iptables中增加了对ipv4的支持,通过以上代码能够简单实现公网接入限制,这也加深了我对netfilter模块中增加match的认识。 
0 0
原创粉丝点击