Chinaunix首页 | 论坛 | 博客
  • 博客访问: 33458
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-25 14:08
文章分类
文章存档

2018年(21)

我的朋友

分类: LINUX

2018-09-19 15:48:31

现在我们以Ipv4 Netfilter自带的扩展target  REJECT 为例,介绍一下怎么使用Netfilter提供的框架来添加自己的target

 

REJECT  TARGET的使用详见iptable使用详解

 

我们看到,在Netfilter中,使用大小写来命名两个名字一样的文件。大写的表示Target,小写的表示Match

例:

xt_hl.c  是扩展match  ttl的文件

Xt_HL.c 是扩展Target ttl的文件。

 

Target REJECT的文件路径:

include/linuc/netfilter_ipv4/ipt_REJECT.h

net/ipv4/netfilter/ipt_REJECT.c

 

 

1、定义自己的target 参数数据结构

enum ipt_reject_with {

       IPT_ICMP_NET_UNREACHABLE,

       IPT_ICMP_HOST_UNREACHABLE,

       IPT_ICMP_PROT_UNREACHABLE,

       IPT_ICMP_PORT_UNREACHABLE,

       IPT_ICMP_ECHOREPLY,

       IPT_ICMP_NET_PROHIBITED,

       IPT_ICMP_HOST_PROHIBITED,

       IPT_TCP_RESET,

       IPT_ICMP_ADMIN_PROHIBITED

};

 

struct ipt_reject_info {

/*拒绝连接后返回icmp报文的类型,由用户指定*/

       enum ipt_reject_with with;      /* reject type */

};

 

2、实现自己的targe处理函数

/*发送icmp回应报文*/

static inline void send_unreach(struct sk_buff *skb_in, int code)

{

       icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);

}

 

static unsigned int reject_tg(struct sk_buff *skb, const struct xt_target_param *par)

{

       /*根据用户的配置来发送相应的ICMP报文,返回DROP,让netfilter丢弃报文*/

const struct ipt_reject_info *reject = par->targinfo;

 

       switch (reject->with) {

       case IPT_ICMP_NET_UNREACHABLE:

              send_unreach(skb, ICMP_NET_UNREACH);

              break;

       case IPT_ICMP_HOST_UNREACHABLE:

              send_unreach(skb, ICMP_HOST_UNREACH);

              break;

       case IPT_ICMP_PROT_UNREACHABLE:

              send_unreach(skb, ICMP_PROT_UNREACH);

              break;

       case IPT_ICMP_PORT_UNREACHABLE:

              send_unreach(skb, ICMP_PORT_UNREACH);

              break;

       case IPT_ICMP_NET_PROHIBITED:

              send_unreach(skb, ICMP_NET_ANO);

              break;

       case IPT_ICMP_HOST_PROHIBITED:

              send_unreach(skb, ICMP_HOST_ANO);

              break;

       case IPT_ICMP_ADMIN_PROHIBITED:

              send_unreach(skb, ICMP_PKT_FILTERED);

              break;

       case IPT_TCP_RESET:

              send_reset(skb, par->hooknum);

       case IPT_ICMP_ECHOREPLY:

              /* Doesn't happen. */

              break;

       }

       return NF_DROP;

}

 

3、实现target entry 的检查函数

该函数在rule格式转换时被调用,来检查用户空间下发的配置是否是正确的。

static bool reject_tg_check(const struct xt_tgchk_param *par)

{

       const struct ipt_reject_info *rejinfo = par->targinfo;

       const struct ipt_entry *e = par->entryinfo;

/*在该版本的内核,回应IPT_ICMP_ECHOREPLY的配置已经不再支持了*/

       if (rejinfo->with == IPT_ICMP_ECHOREPLY) {

              printk("ipt_REJECT: ECHOREPLY no longer supported.\n");

              return false;

       }

/*如果回应报文类型为TCP连接重置,match中必须指定为tcp报文*/

else if (rejinfo->with == IPT_TCP_RESET) {

              /* Must specify that it's a TCP packet */

              if (e->ip.proto != IPPROTO_TCP

                  || (e->ip.invflags & XT_INV_PROTO)) {

                     printk("ipt_REJECT: TCP_RESET invalid for non-tcp\n");

                     return false;

              }

       }

/*检查通过,返回true*/

       return true;

}

 

4、初始化xt_target实例

static struct xt_target reject_tg_reg __read_mostly = {

       .name             = "REJECT",

       .family           = NFPROTO_IPV4,

       .target            = reject_tg,

       .targetsize       = sizeof(struct ipt_reject_info),

       .table             = "filter",  //该target只能用于filter表

       .hooks            = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) |

                       (1 << NF_INET_LOCAL_OUT),

       .checkentry     = reject_tg_check,

       .me         = THIS_MODULE,

};

5、xt_target注册到Netfilter

static int __init reject_tg_init(void)

{

       return xt_register_target(&reject_tg_reg);

}

 

module_init(reject_tg_init);

 

(未完待续)

 

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