分类: LINUX
2014-10-16 16:55:24
现在我们以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);
(未完待续)