本文参考自(十四)洞悉linux下的Netfilter&iptables:开发一个match模块【实战】,修复了其中的一些错误,并适配3.x以上的内核和netfilter版本,模块在centos7(kernel 3.10\iptables1.4.21)工作正常。
内核扩展 ipt_pktsize.c
-
#include <linux/module.h>
-
#include <linux/skbuff.h>
-
#include <linux/ip.h>
-
#include <linux/version.h>
-
#include <linux/netfilter_ipv4/ip_tables.h>
-
-
MODULE_AUTHOR("pole");
-
MODULE_DESCRIPTION("iptables modules: frame size range match.");
-
MODULE_LICENSE("GPL");
-
-
#define PKTSIZE_VERSION "0.1"
-
struct ipt_pktsize_info {
-
u_int32_t min_pktsize,max_pktsize;
-
};
-
-
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9))
-
/* for xtables */
-
static bool
-
match(const struct sk_buff *skb, struct xt_action_param *par)
-
{
-
const struct ipt_pktsize_info *info = par->matchinfo;
-
-
//int len = skb->len; // eth data part len
-
int len = skb->len + skb->mac_len; // frame len including eth head
-
//const struct iphdr *iph = ip_hdr(skb);
-
//int len = ntohs(iph->tot_len)-(iph->ihl*4); // ip data len ntohs(iph->tot_len) = skb->len
-
-
if(len >= info->min_pktsize && len <= info->max_pktsize)
-
{
-
printk(KERN_EMERG " ipt_pktsize: hit a pkt len %u in %u~%u \n", len, info->min_pktsize, info->max_pktsize);
-
return true;
-
}
-
-
return false;
-
}
-
-
-
#else
-
#error /* ancient iptables */
-
static int
-
match(const struct sk_buff *skb,
-
const struct net_device *in,
-
const struct net_device *out,
-
const struct xt_match *match,
-
const void *matchinfo,
-
int offset,
-
unsigned int protoff,
-
int *hotdrop)
-
{
-
const struct ipt_pktsize_info *info = matchinfo;
-
const struct iphdr *iph = ip_hdr(skb);
-
-
int pkttruesize = ntohs(iph->tot_len)-(iph->ihl*4);
-
printk(KERN_INFO "****** iph->tot_len = %d, iph->ihl = %d\n", iph->tot_len, iph->ihl);
-
printk(KERN_INFO " skb->len = %d, skb->data_len = %d\n", iph->tot_len, iph->ihl);
-
-
if(pkttruesize>=info->min_pktsize && pkttruesize <=info->max_pktsize){
-
return 1;
-
}
-
else{
-
return 0;
-
}
-
return 1;
-
}
-
-
#endif
-
-
-
static struct xt_match pktsize_match = {
-
.name = "pktsize",
-
.family = NFPROTO_IPV4,
-
.match = match,
-
.matchsize = sizeof(struct ipt_pktsize_info),
-
.destroy = NULL,
-
.me = THIS_MODULE,
-
};
-
-
-
static int __init init(void)
-
{
-
printk(KERN_INFO "pktsize module loading\n");
-
return xt_register_match(&pktsize_match);
-
}
-
-
static void __exit fini(void)
-
{
-
xt_unregister_match(&pktsize_match);
-
printk(KERN_INFO "pktsize module unloaded\n");
-
}
-
-
module_init(init);
-
module_exit(fini);
用户态 libipt_pktsize.c
-
#include <stdio.h>
-
#include <netdb.h>
-
#include <string.h>
-
#include <stdlib.h>
-
#include <getopt.h>
-
#include <ctype.h>
-
-
#include <iptables.h>
-
-
#define PKTSIZE_VERSION "0.1"
-
struct ipt_pktsize_info {
-
u_int32_t min_pktsize,max_pktsize;
-
};
-
-
#undef OLD_PARSER
-
-
#if 1
-
#define dbg_print(arg...) printf(arg)
-
#else
-
#define dbg_print(arg...)
-
#endif
-
-
-
#ifdef OLD_PARSER
-
static struct option opts[] = {
-
{ "size", 1, NULL, '1' },
-
{0}
-
};
-
#else
-
enum {
-
O_SIZE = 0,
-
O_BURST,
-
};
-
static const struct xt_option_entry pktsize_opts[] = {
-
{.name = "size", .id = O_SIZE, .type = XTTYPE_STRING},
-
XTOPT_TABLEEND
-
};
-
#endif
-
-
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);
-
}
-
-
-
/* 输入参数的可能格式为如下:
-
xx 指定数据包大小 XX
-
:XX 范围是0~XX
-
YY: 范围是YY~65535
-
xx:YY 范围是XX~YY
-
*/
-
static void parse_pkts(const char* s,struct ipt_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);
-
}
-
-
#ifdef OLD_PARSER
-
static int
-
parse(int c, char **argv, int invert, unsigned int *flags,
-
const void *entry,
-
struct ipt_entry_match **match)
-
{
-
struct ipt_pktsize_info *info = (struct ipt_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 usage type: iptables -m pktsize --help\n");
-
}
-
-
#else
-
static void pktsize_parse(struct xt_option_call *cb)
-
{
-
struct ipt_pktsize_info *info = cb->data;
-
xtables_option_parse(cb);
-
-
dbg_print(" %s-%d, args: %s \n", __FUNCTION__, __LINE__, cb->arg);
-
switch (cb->entry->id)
-
{
-
case O_SIZE:
-
parse_pkts(cb->arg, info);
-
break;
-
}
-
-
if (cb->invert)
-
xtables_error(PARAMETER_PROBLEM,
-
" does not support invert");
-
}
-
-
static void pktsize_fcheck(struct xt_fcheck_call *cb)
-
{
-
if (cb->xflags == 0)
-
xtables_error(PARAMETER_PROBLEM,
-
"pktsize match: Parameter --size is required, resort to -h");
-
}
-
#endif
-
-
-
static void __print(struct ipt_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 print(const void *ip, const struct ipt_entry_match *match, int numeric)
-
{
-
printf("size ");
-
__print((struct ipt_pktsize_info *)match->data);
-
-
}
-
-
static void save(const void *ip, const struct ipt_entry_match *match)
-
{
-
printf("--size ");
-
__print((struct ipt_pktsize_info *)match->data);
-
}
-
-
-
static struct xtables_match pktsize_match = {
-
.next = NULL,
-
.name = "pktsize",
-
.version = XTABLES_VERSION,
-
.family = NFPROTO_IPV4,
-
.size = XT_ALIGN(sizeof(struct ipt_pktsize_info)),
-
.userspacesize = XT_ALIGN(sizeof(struct ipt_pktsize_info)),
-
.help = help,
-
#ifdef OLD_PARSER
-
.parse = parse,
-
.final_check = final_check,
-
.extra_opts = opts,
-
#else
-
.x6_parse = pktsize_parse,
-
.x6_fcheck = pktsize_fcheck,
-
.x6_options = pktsize_opts,
-
#endif
-
.print = print,
-
.save = save,
-
};
-
-
-
void _init(void)
-
{
-
xtables_register_match(&pktsize_match);
-
}
Makefile
编译用户态扩展so时,需要下载iptables源码包,下载
-
CC=gcc
-
LD=ld
-
-
IPTABLES_SRC=/home/pole/work/net/iptables-1.4.21
-
INCLUDE=-I$(IPTABLES_SRC)/include
-
-
PKG:=ipt_pktsize
-
name_ko:=$(PKG)
-
name_so:=lib$(PKG)
-
ipt_ko=$(name_ko).ko
-
ipt_so=$(name_so).so
-
-
-
all: kmod lib
-
#kmod: $(ipt_ko)
-
#lib: $(ipt_so)
-
-
# compile kernel module
-
KERNEL_SRC=/lib/modules/`uname -r`/build
-
obj-m:=$(PKG).o
-
kmod: $(name_ko).c
-
$(MAKE) -C $(KERNEL_SRC) SUBDIRS=$(PWD) modules
-
-
# compile user lib
-
lib: $(name_so).c
-
$(CC) $(INCLUDE) -fPIC -c $(name_so).c
-
$(LD) -shared -o $(ipt_so) $(name_so).o
-
-
clean:
-
@rm -rf *.o *.so *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
-
-
install: all
-
cp -rf $(ipt_so) /usr/lib64/xtables/
-
cp -rf $(ipt_ko) /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/
-
@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) |