netfilter(2) 自定义match模块

PpikachuP 2019-06-21

代码

先贴上代码,后续再添加解释
uname -r 3.10.0-514.el7.x86_64

用户态代码

/*xt_pktsize.h /usr/inlcude/linux/netfilter_ipv4/*/

  1 #ifndef __IPT_PKTSIZE_H
  2 #define __IPT_PKTSIZE_H
  3 
  4 #define PKTSIZE_VERSION "0.1"
  5 
  6 struct xt_pktsize_info {
  7     u_int32_t min_pktsize,max_pktsize;
  8 };
  9 
 10 #endif
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/xt_pktsize.h>

static void __parse_pkts(const char* s,struct xt_pktsize_info *info);
static void __print(struct xt_pktsize_info *info);

static struct option opts[] = {
        { "size", 1, NULL, '1' },
        {0}
};

static void help(void)
{
    printf(
    "pktsize v%s options:\n"
    " --size size[:size]        Match packet size against value or range\n"
    "\nExamples:\n"
    " iptables -A FORWARD -m pktsize --size 65 -j DROP\n"
    " iptables -A FORWARD -m pktsize --size 80:120 -j DROP\n"
    , PKTSIZE_VERSION);
}

/* Parse CLI parameters to xt_entry_match struct. And xtables_match.name will be copied to xt_entry_match struct
 * In kernel space, the same xt_entry_match will be used to find correspond kenel match mode which is xt_match
 */
static int parse(int c, char **argv, int invert, unsigned int *flags
                , const void *entry
                , struct xt_entry_match **match)
{
   struct xt_pktsize_info *info = (struct xt_pktsize_info *)(*match)->data;
   switch(c){
      case '1':
        if (*flags)
           xtables_error(PARAMETER_PROBLEM,
                      "size: `--size' may only be "
                      "specified once");
        __parse_pkts(argv[optind-1], info);
        *flags = 1;
      break;
      default:
        return 0;
   }
   return 1;
}

static void final_check(unsigned int flags)
{
    if(!flags)
        xtables_error(PARAMETER_PROBLEM,"\npktsize-parameter problem: for pktsize useage type: iptables -m pktsize --help\n"); 
}

static void print(const void *ip, const struct xt_entry_match *match, int numeric)
{
    printf("size ");
    __print((struct xt_pktsize_info*)match->data);
}

static void save(const void *ip, const struct xt_entry_match *match)
{
    printf("--size ");
    __print((struct xt_pktsize_info *)match->data);
}

static struct xtables_match pktsize=
{
    .name   = "pktsize",
    .version= XTABLES_VERSION,
    .family = NFPROTO_IPV4,
    .size   = XT_ALIGN(sizeof(struct xt_pktsize_info)),
    .userspacesize= XT_ALIGN(sizeof(struct xt_pktsize_info)),
    .help   = help,
    .parse  = parse,
    .final_check= final_check,
    .print  = print,
    .save   = save,
    .extra_opts = opts
};

void _init(void)
{
    xtables_register_match(&pktsize);
}

static void __print(struct xt_pktsize_info *info)
{
    if (info->max_pktsize == info->min_pktsize)
        printf("%u ", info->min_pktsize);
    else
        printf("%u:%u ", info->min_pktsize, info->max_pktsize);
}

static void __parse_pkts(const char* s,struct xt_pktsize_info *info)
{
   char* buff,*cp;
   buff = strdup(s);
 
   if(NULL == (cp=strchr(buff,':'))){
      info->min_pktsize = info->max_pktsize = strtol(buff,NULL,0);
   }else{
      *cp = '\0';
      cp++;
 
      info->min_pktsize = strtol(buff,NULL,0);
      info->max_pktsize = (cp[0]? strtol(cp,NULL,0):0xFFFF);
   }
 
   free(buff);
 
   if (info->min_pktsize > info->max_pktsize)
       xtables_error(PARAMETER_PROBLEM,
                "pktsize min. range value `%u' greater than max. "
                "range value `%u'", info->min_pktsize, info->max_pktsize);
}

内核态代码

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/version.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/xt_pktsize.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("Netfilter Module");

static bool match(const struct sk_buff *skb,struct xt_action_param *param)
{
    const struct xt_pktsize_info *info = param->matchinfo;
    const struct iphdr *iph = ip_hdr(skb);

    int truesize = ntohs(iph->tot_len)-(iph->ihl*4);

    if(truesize >= info->min_pktsize && truesize <= info->max_pktsize)
        return 1;
    else
        return 0;

    return 1;

}

static struct xt_match pktsize_match = {
    .name   = "pktsize",
    .family = AF_INET,
    .match  = match,
    .matchsize = sizeof(struct xt_pktsize_info),
    .destroy= NULL,
    .me     = THIS_MODULE,    
};

static int __init init(void)
{
    return xt_register_match(&pktsize_match);
}

static void __exit fini(void)
{
    xt_unregister_match(&pktsize_match);
}

module_init(init);
module_exit(fini);

使用

iptables -A INPUT -m pktsize --size 60:100 -j DROP
使用 ping -s 80 会发现不通了。

相关推荐