自己写 Netfilter 匹配器

  看了Nicolas写的netfilter写匹配器,自己尝试编译测试,发现iptables 以及内核版本升级很多数据结构和函数接口都改变了,需要做大量的修改才能运行。


运行 iptables/netfilter

1)iptables

从 ftp://ftp.netfilter.org/pub/iptables/ 下载iptables 的源码然后拷贝libipt_ipaddr.c 到 iptables-1.4.10/extensions.

拷贝ipt_ipaddr.h 到 ./include/linux/netfilter_ipv4/

然后 

$./configure 
$make && make install


2)ipaddr.ko

编译这个内核模块需用到3个文件:

ipt_ipaddr.h  ipt_ipaddr.c  Makefile



编译完内核模块之后用

$ sudo modprobe x_tables
$ sudo insmod ipaddr.ko
加载内核模块,然后iptables命令:

sudo iptables -I OUTPUT -m ipaddr --ipsrc ipaddr --ipdst  ipaddr
设置规则。

修改后的源码:

ipt_ipaddr.c :
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/netfilter_ipv4.h>

#include <linux/netfilter_ipv4/ip_tables.h>

#include "ipt_ipaddr.h"


#define NIPQUAD(addr) \
    ((unsigned char *)&addr)[0], \
    ((unsigned char *)&addr)[1], \
    ((unsigned char *)&addr)[2], \
    ((unsigned char *)&addr)[3]


#define NF_IP_LOCAL_IN          1
#define NF_IP_LOCAL_OUT         3



static int ipt_match(const struct sk_buff *skb,struct xt_action_param *param)
{
   const struct net_device *in = param->in;
   const struct net_device *out = param->out;	
   const struct ipt_ipaddr_info *info  = param->matchinfo;

   struct iphdr *iph = ip_hdr(skb);
   printk("entered ipt_match !\n");
   printk(KERN_INFO "ipt_ipaddr: IN=%s OUT=%s TOS=0x%02X "
                    "TTL=%x SRC=%u.%u.%u.%u DST=%u.%u.%u.%u "
                    "ID=%u IPSRC=%u.%u.%u.%u IPDST=%u.%u.%u.%u\n",

                    in ? (char *)in : "", out ? (char *)out : "", iph->tos,
                    iph->ttl, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
                    ntohs(iph->id), NIPQUAD(info->ipaddr.src), NIPQUAD(info->ipaddr.dst)
         );

   if (info->flags & IPADDR_SRC) {
      if ( (ntohl(iph->saddr) != ntohl(info->ipaddr.src)) ^ !!(info->flags & IPADDR_SRC_INV) ) {
         
         printk(KERN_NOTICE "src IP %u.%u.%u.%u is not matching %s.\n",
                            NIPQUAD(info->ipaddr.src),
                            info->flags & IPADDR_SRC_INV ? " (INV)" : "");
         return 0;
      }
   }

   if (info->flags & IPADDR_DST) {
      if ( (ntohl(iph->daddr) != ntohl(info->ipaddr.dst)) ^ !!(info->flags & IPADDR_DST_INV) )  {

         printk(KERN_NOTICE "dst IP %u.%u.%u.%u is not matching%s.\n",
                            NIPQUAD(info->ipaddr.dst),
                            info->flags & IPADDR_DST_INV ? " (INV)" : "");
         return 0;
      }
   }
   
   return 1;
}

static int ipaddr_checkentry(const struct xt_mtchk_param *param)
{
   printk("entered ipaddr_checkentry\n");
   const struct ipt_ipaddr_info *info = param->matchinfo;
   unsigned int hook_mask = param->hook_mask;
   unsigned int matchsize = param->match->matchsize;
   char tablename[XT_TABLE_MAXNAMELEN];
   const struct ipt_ip *ip = (struct ipt_ip *)param->entryinfo;		// this is specified by param->family.

   if (hook_mask & ~((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) {
      printk(KERN_WARNING "ipt_ipaddr: only valid with the FILTER table.\n");
      return 0;
   }

   if (matchsize != XT_ALIGN(sizeof(struct ipt_ipaddr_info))) {
      printk(KERN_ERR "ipt_ipaddr: matchsize differ, you may have forgotten to recompile me.\n");
      return 0;
   }

   strcpy(tablename,param->match->table);
   printk(KERN_INFO "ipt_ipaddr: Registered in the %s table, hook=%x, proto=%u\n",
                    tablename, hook_mask, ip->proto);

   return 1;
}

static struct xt_match ipaddr_match  = { 
        .match	= ipt_match,
	.matchsize = XT_ALIGN(sizeof(struct ipt_ipaddr_info)),	/// without this may cause invalid size 0 != 12
	.name 	= "ipaddr",
	.checkentry = ipaddr_checkentry, 
	.me 	= THIS_MODULE 
};


static int __init init(void)
{
   printk(KERN_INFO "ipt_ipaddr: init!\n");
   return xt_register_match(&ipaddr_match);
}

static void __exit fini(void)
{
   printk(KERN_INFO "ipt_ipaddr: exit!\n");
   xt_unregister_match(&ipaddr_match);
}

module_init(init);
module_exit(fini);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicolas Bouliane && Samuel Jean");
MODULE_DESCRIPTION("netfilter module skeleton");

ipt_ipaddr.h
#ifndef _IPT_IPADDR_H
#define _IPT_IPADDR_H


#include <linux/types.h>

#define IPADDR_SRC   0x01     /* Match source IP addr */
#define IPADDR_DST   0x02     /* Match destination IP addr */

#define IPADDR_SRC_INV  0x10  /* Negate the condition */
#define IPADDR_DST_INV  0x20  /* Negate the condition */

struct ipt_ipaddr {
   __u32 src, dst;
};

struct ipt_ipaddr_info {

   struct ipt_ipaddr ipaddr;
   
   /* Flags from above */
   __u8 flags;
   
};

#endif  


libipt_ipaddr.c:
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iptables.h>

#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_ipaddr.h>


//./configure --prefix= ./install 
/* 
 * 	./install/sbin/iptables -m ipaddr -h
 */
static void ipaddr_help(void)
{
   printf (
            "IPADDR  options:\n"
            "[!] --ipsrc <ip>\t\t The incoming ip addr matches.\n"
            "[!] --ipdst <ip>\t\t The outgoing ip addr matches.\n"
            "\n"
         );
}

static struct option ipaddr_opts[] = {
   { .name = "ipsrc",   .has_arg = 1,   .flag = 0,   .val = '1' },
   { .name = "ipdst",   .has_arg = 1,   .flag = 0,   .val = '2' },
   { .name = 0 }
};

static void ipaddr_init(struct xt_entry_match *m)
{
   /* Can't cache this 
   *nfcache |= NFC_UNKNOWN;*/
}


__be32 in_aton(const char *str)
{
	unsigned long l;
	unsigned int val;
	int i;

	l = 0;
	for (i = 0; i < 4; i++)
	{
		l <<= 8;
		if (*str != '\0')
		{
			val = 0;
			while (*str != '\0' && *str != '.' && *str != '\n')
			{
				val *= 10;
				val += *str - '0';
				str++;
			}
			l |= val;
			if (*str != '\0')
				str++;
		}
	}
	return htonl(l);
}


struct in_addr* dotted_to_addr(const char *arg)
{
	struct in_addr * p;
	p = malloc(sizeof(struct in_addr));
	printf("%x\n",p);
	p->s_addr = in_aton(arg);
	return p;	
}

static void parse_ipaddr(const char *arg, __u32 *ipaddr)
{
   struct in_addr *ip;
   printf("in parse_ipaddr arg is %s",arg);
   ip = dotted_to_addr(arg);
   if (!ip)
      xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Bad IP address `%s'\n", arg);

   *ipaddr = ip->s_addr;
}

static int ipaddr_parse(int c, char **argv, int invert, unsigned int *flags,
                 const struct ipt_entry *entry,
                 struct ipt_entry_match **match)
{
   struct ipt_ipaddr_info *info = (struct ipt_ipaddr_info *)(*match)->data /*NULL*/;
   printf("entered ipaddr_parse\n");
   switch(c) {
      case '1':
         if (*flags & IPADDR_SRC)
            xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipsrc once!");
         *flags |= IPADDR_SRC;

         info->flags |= IPADDR_SRC;
         if (invert)
            info->flags |= IPADDR_SRC_INV;

         parse_ipaddr(argv[optind-1], &info->ipaddr.src);
         break;

      case '2':
         if (*flags & IPADDR_DST)
            xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipdst once!");
         *flags |= IPADDR_DST;

         info->flags |= IPADDR_DST;
         if (invert)
            info->flags |= IPADDR_DST_INV;

         parse_ipaddr(argv[optind-1], &info->ipaddr.dst);
         break;

      default:
         return 0;
   }

   return 1;
}

static void ipaddr_final_check(unsigned int flags)
{
   if (!flags)
      xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Invalid parameters.");
}

/* 
 * Can't call it ipaddr, because
 * the main structure is already
 * called like that.
 */
static void print_ipaddr(__u32 *ip_addr)
{
   printf(  "%u.%u.%u.%u ", 
            ((unsigned char *)ip_addr)[0],
            ((unsigned char *)ip_addr)[1],
            ((unsigned char *)ip_addr)[2],
            ((unsigned char *)ip_addr)[3]
         );
}

static void ipaddr_print(const struct ipt_ip *ip,
                  const struct ipt_entry_match *match,
                  int numeric)
{
   const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
   printf("entered ipaddr_print\n");
   if (info->flags & IPADDR_SRC) {
         printf("src IP ");
      if (info->flags & IPADDR_SRC_INV)
         printf("! ");
      print_ipaddr((__u32 *)&info->ipaddr.src);
   }

   if (info->flags & IPADDR_DST) {
      printf("dst IP ");
      if (info->flags & IPADDR_DST_INV)
         printf("! ");
      print_ipaddr((__u32 *)&info->ipaddr.dst);
   }
}

/* 
 * iptables-saves
 */
static void ipaddr_save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
   const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
   printf("entered ipaddr_save\n");
   if (info->flags & IPADDR_SRC) {
      if (info->flags & IPADDR_SRC_INV)
         printf("! ");
      printf("--ipsrc ");
      print_ipaddr((__u32 *)&info->ipaddr.src);
   }

   if (info->flags & IPADDR_DST) {
      if (info->flags & IPADDR_DST_INV)
         printf("! ");
      printf("--ipdst ");
      print_ipaddr((__u32 *)&info->ipaddr.dst);
   }
}

static struct xtables_match ipaddr = {
    .family	     = NFPROTO_UNSPEC,
    .name            = "ipaddr",
    .version         = XTABLES_VERSION,
    .size            = XT_ALIGN(sizeof(struct ipt_ipaddr_info)),
    .userspacesize   = XT_ALIGN(sizeof(struct ipt_ipaddr_info)),
    .help            = ipaddr_help,
   /// .init            = ipaddr_init,
    .parse           = ipaddr_parse,
    .final_check     = ipaddr_final_check,
    .print           = ipaddr_print,
    .save            = ipaddr_save,
    .extra_opts      = ipaddr_opts
};

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



Makefile文件:
EXTRA_CFLAGS	:= -g -O2	##Debug info .
KVERS = $(shell uname -r)

ifneq ($(KERNELRELEASE),)

obj-m			= ipaddr.o

ipaddr-objs 	        := ipt_ipaddr.o
else
KDIR := /lib/modules/$(KVERS)/build

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.order *~  *.symvers

endif




原文链接:
http://www.linuxfocus.org/ChineseGB/February2005/article367.shtml



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值