Chinaunix首页 | 论坛 | 博客
  • 博客访问: 713949
  • 博文数量: 79
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1338
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-12 08:51
个人简介

XMU->九天揽月->五湖抓鳖->DSP->driver->kernel/OpenWRT->ISP/RTOS

文章分类

全部博文(79)

文章存档

2020年(2)

2018年(3)

2016年(7)

2015年(42)

2014年(25)

分类: LINUX

2015-09-01 20:59:56

本文参考自(十四)洞悉linux下的Netfilter&iptables:开发一个match模块【实战】修复了其中的一些错误,并适配3.x以上的内核和netfilter版本,模块在centos7(kernel 3.10\iptables1.4.21)工作正常

内核扩展 ipt_pktsize.c
  1. #include <linux/module.h>
  2. #include <linux/skbuff.h>
  3. #include <linux/ip.h>
  4. #include <linux/version.h>
  5. #include <linux/netfilter_ipv4/ip_tables.h>

  6. MODULE_AUTHOR("pole");
  7. MODULE_DESCRIPTION("iptables modules: frame size range match.");
  8. MODULE_LICENSE("GPL");

  9. #define PKTSIZE_VERSION "0.1"
  10. struct ipt_pktsize_info {
  11.     u_int32_t min_pktsize,max_pktsize;
  12. };

  13. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9))
  14. /* for xtables */
  15. static bool
  16. match(const struct sk_buff *skb, struct xt_action_param *par)
  17. {
  18.     const struct ipt_pktsize_info *info = par->matchinfo;
  19.     
  20.     //int len = skb->len; // eth data part len
  21.     int len = skb->len + skb->mac_len; // frame len including eth head
  22.     //const struct iphdr *iph = ip_hdr(skb);
  23.     //int len = ntohs(iph->tot_len)-(iph->ihl*4); // ip data len ntohs(iph->tot_len) = skb->len

  24.     if(len >= info->min_pktsize && len <= info->max_pktsize)
  25.     {
  26.         printk(KERN_EMERG " ipt_pktsize: hit a pkt len %u in %u~%u \n", len, info->min_pktsize, info->max_pktsize);
  27.         return true;
  28.     }
  29.     
  30.     return false;
  31. }


  32. #else
  33. #error /* ancient iptables */
  34. static int
  35. match(const struct sk_buff *skb,
  36.       const struct net_device *in,
  37.       const struct net_device *out,
  38.       const struct xt_match *match,
  39.       const void *matchinfo,
  40.       int offset,
  41.       unsigned int protoff,
  42.       int *hotdrop)
  43. {
  44.         const struct ipt_pktsize_info *info = matchinfo;
  45.         const struct iphdr *iph = ip_hdr(skb);

  46.         int pkttruesize = ntohs(iph->tot_len)-(iph->ihl*4);
  47.         printk(KERN_INFO "****** iph->tot_len = %d, iph->ihl = %d\n", iph->tot_len, iph->ihl);
  48.         printk(KERN_INFO " skb->len = %d, skb->data_len = %d\n", iph->tot_len, iph->ihl);

  49.         if(pkttruesize>=info->min_pktsize && pkttruesize <=info->max_pktsize){
  50.                 return 1;
  51.         }
  52.         else{
  53.                 return 0;
  54.         }
  55.     return 1;
  56. }

  57. #endif


  58. static struct xt_match pktsize_match = {
  59.         .name = "pktsize",
  60.         .family = NFPROTO_IPV4,
  61.         .match = match,
  62.         .matchsize = sizeof(struct ipt_pktsize_info),
  63.         .destroy = NULL,
  64.         .me = THIS_MODULE,
  65. };


  66. static int __init init(void)
  67. {
  68.     printk(KERN_INFO "pktsize module loading\n");
  69.     return xt_register_match(&pktsize_match);
  70. }

  71. static void __exit fini(void)
  72. {
  73.     xt_unregister_match(&pktsize_match);
  74.     printk(KERN_INFO "pktsize module unloaded\n");
  75. }

  76. module_init(init);
  77. module_exit(fini);

用户态 libipt_pktsize.c
  1. #include <stdio.h>
  2. #include <netdb.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <getopt.h>
  6. #include <ctype.h>

  7. #include <iptables.h>

  8. #define PKTSIZE_VERSION "0.1"
  9. struct ipt_pktsize_info {
  10.     u_int32_t min_pktsize,max_pktsize;
  11. };

  12. #undef OLD_PARSER

  13. #if 1
  14. #define dbg_print(arg...) printf(arg)
  15. #else
  16. #define dbg_print(arg...)
  17. #endif


  18. #ifdef OLD_PARSER
  19. static struct option opts[] = {
  20.         { "size", 1, NULL, '1' },
  21.         {0}
  22. };
  23. #else
  24. enum {
  25.         O_SIZE = 0,
  26.         O_BURST,
  27. };
  28. static const struct xt_option_entry pktsize_opts[] = {
  29.         {.name = "size", .id = O_SIZE, .type = XTTYPE_STRING},
  30.         XTOPT_TABLEEND
  31. };
  32. #endif

  33. static void help(void)
  34. {
  35.     printf(
  36.     "pktsize v%s options:\n"
  37.     " --size size[:size] Match packet size against value or range\n"
  38.     "\nExamples:\n"
  39.     " iptables -A FORWARD -m pktsize --size 65 -j DROP\n"
  40.     " iptables -A FORWARD -m pktsize --size 80:120 -j DROP\n"
  41.     , PKTSIZE_VERSION);
  42. }


  43. /* 输入参数的可能格式为如下:
  44.     xx 指定数据包大小 XX
  45.     :XX 范围是0~XX
  46.     YY: 范围是YY~65535
  47.     xx:YY 范围是XX~YY
  48. */
  49. static void parse_pkts(const char* s,struct ipt_pktsize_info *info){
  50.         char* buff,*cp;
  51.         
  52.         buff = strdup(s);

  53.         if(NULL == (cp=strchr(buff,':'))){
  54.                 info->min_pktsize = info->max_pktsize = strtol(buff,NULL,0);
  55.         }else{
  56.                 *cp = '\0';
  57.                 cp++;

  58.                 info->min_pktsize = strtol(buff,NULL,0);
  59.                 info->max_pktsize = (cp[0]? strtol(cp,NULL,0):0xFFFF);
  60.         }

  61.         free(buff);

  62.         if (info->min_pktsize > info->max_pktsize)
  63.                 xtables_error(PARAMETER_PROBLEM,
  64.                            "pktsize min. range value `%u' greater than max. "
  65.                            "range value `%u'", info->min_pktsize, info->max_pktsize);
  66. }

  67. #ifdef OLD_PARSER
  68. static int
  69. parse(int c, char **argv, int invert, unsigned int *flags,
  70.         const void *entry,
  71.         struct ipt_entry_match **match)
  72. {
  73.         struct ipt_pktsize_info *info = (struct ipt_pktsize_info *)(*match)->data;
  74.         switch(c){
  75.                 case '1':
  76.                         if (*flags)
  77.                                 xtables_error(PARAMETER_PROBLEM,
  78.                                            "size: `--size' may only be "
  79.                                            "specified once");
  80.                         parse_pkts(argv[optind-1], info);
  81.                         *flags = 1;
  82.                         break;
  83.                 default:
  84.                         return 0;
  85.         }
  86.         return 1;
  87. }

  88. static void final_check(unsigned int flags)
  89. {
  90.     if (!flags)
  91.             xtables_error(PARAMETER_PROBLEM,
  92.             "\npktsize-parameter problem: for pktsize usage type: iptables -m pktsize --help\n");
  93. }

  94. #else
  95. static void pktsize_parse(struct xt_option_call *cb)
  96. {
  97.         struct ipt_pktsize_info *info = cb->data;
  98.         xtables_option_parse(cb);

  99.         dbg_print(" %s-%d, args: %s \n", __FUNCTION__, __LINE__, cb->arg);
  100.         switch (cb->entry->id)
  101.         {
  102.             case O_SIZE:
  103.                 parse_pkts(cb->arg, info);
  104.                 break;
  105.         }
  106.         
  107.         if (cb->invert)
  108.                 xtables_error(PARAMETER_PROBLEM,
  109.                            " does not support invert");
  110. }

  111. static void pktsize_fcheck(struct xt_fcheck_call *cb)
  112. {
  113.     if (cb->xflags == 0)
  114.         xtables_error(PARAMETER_PROBLEM,
  115.          "pktsize match: Parameter --size is required, resort to -h");
  116. }
  117. #endif


  118. static void __print(struct ipt_pktsize_info * info)
  119. {
  120.         if (info->max_pktsize == info->min_pktsize)
  121.                 printf("%u ", info->min_pktsize);
  122.         else
  123.                 printf("%u:%u ", info->min_pktsize, info->max_pktsize);
  124. }

  125. static void print(const void *ip, const struct ipt_entry_match *match, int numeric)
  126. {
  127.         printf("size ");
  128.         __print((struct ipt_pktsize_info *)match->data);

  129. }

  130. static void save(const void *ip, const struct ipt_entry_match *match)
  131. {
  132.         printf("--size ");
  133.         __print((struct ipt_pktsize_info *)match->data);
  134. }


  135. static struct xtables_match pktsize_match = {
  136.     .next = NULL,
  137.     .name = "pktsize",
  138.     .version = XTABLES_VERSION,
  139.     .family = NFPROTO_IPV4,
  140.     .size = XT_ALIGN(sizeof(struct ipt_pktsize_info)),
  141.     .userspacesize = XT_ALIGN(sizeof(struct ipt_pktsize_info)),
  142.     .help = help,
  143.     #ifdef OLD_PARSER
  144.     .parse = parse,
  145.     .final_check = final_check,
  146.     .extra_opts = opts,
  147.     #else
  148.     .x6_parse = pktsize_parse,
  149.     .x6_fcheck = pktsize_fcheck,
  150.     .x6_options = pktsize_opts,
  151.     #endif
  152.     .print = print,
  153.     .save = save,
  154. };


  155. void _init(void)
  156. {
  157.     xtables_register_match(&pktsize_match);
  158. }

Makefile
编译用户态扩展so时,需要下载iptables源码包,下载

  1. CC=gcc
  2. LD=ld
  3.   
  4. IPTABLES_SRC=/home/pole/work/net/iptables-1.4.21
  5. INCLUDE=-I$(IPTABLES_SRC)/include

  6. PKG:=ipt_pktsize
  7. name_ko:=$(PKG)
  8. name_so:=lib$(PKG)
  9. ipt_ko=$(name_ko).ko
  10. ipt_so=$(name_so).so
  11.   
  12.   
  13. all: kmod lib
  14. #kmod: $(ipt_ko)
  15. #lib: $(ipt_so)

  16. # compile kernel module
  17. KERNEL_SRC=/lib/modules/`uname -r`/build
  18. obj-m:=$(PKG).o
  19. kmod: $(name_ko).c
  20.     $(MAKE) -C $(KERNEL_SRC) SUBDIRS=$(PWD) modules

  21. # compile user lib
  22. lib: $(name_so).c
  23.     $(CC) $(INCLUDE) -fPIC -c $(name_so).c
  24.     $(LD) -shared -o $(ipt_so) $(name_so).o

  25. clean:
  26.     @rm -rf *.o *.so *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions

  27. install: all
  28.     cp -rf $(ipt_so) /usr/lib64/xtables/
  29.     cp -rf $(ipt_ko) /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/
  30.     @depmod -a

加载ipt_pktsize.ko和libipt_pktsize.so
sudo iptables -t mangle -A OUTPUT -p icmp -m pktsize --size 1200:1500 -j DROP
测试 ping $ip -s 1300 ,这时候会看到由于Pktsize规则可以匹配,icmp请求被防火墙拒绝发送。

阅读(3919) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~