Netfilter之DNAT和SNAT
一.概述
在netfilter中有四个表,filter表, nat表, mangle表, raw表;其中常用的前三个表。Filter表执行过滤的功能,如包的放行,丢弃,转发至用户地址空间等;nat表,包的源地址或者目标地址转换等;mangle表,对包的参数就行更改,如设置mark值, ttl值等。本文重点描述nat表。
二.Nat表
2.1初始化
static int __initnf_nat_standalone_init(void)
{
intret = 0;
……………….
ret= nf_nat_rule_init(); //初始化nat表
……………….
ret= nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); //注册NF_HOOK()中的钩子函数,定义在结构体nf_nat_ops,该结构体函数被定义到框架nf_hooks[NPROTO][NF_MAX_HOOKS]中。
………………..
returnret;
}
2.2钩子结构体nf_nat_ops
static struct nf_hook_ops nf_nat_ops[]__read_mostly = {
/*Before packet filtering, change destination */
{
.hook =nf_nat_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_NAT_DST,
},
/*After packet filtering, change source */
{
.hook =nf_nat_out,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_NAT_SRC,
},
/*Before packet filtering, change destination */
{
.hook =nf_nat_local_fn,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_NAT_DST,
},
/*After packet filtering, change source */
{
.hook =nf_nat_fn,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_NAT_SRC,
},
};
2.3表和target函数的定义
int __init nf_nat_rule_init(void)
{
intret;
……………….
nat_table= ipt_register_table(&init_net, &__nat_table,
&nat_initial_table.repl);
……………….
ret= xt_register_target(&ipt_snat_reg);
……………….
ret= xt_register_target(&ipt_dnat_reg);//看下文将该target注册到链表xt[af].target
……………….
returnret;
}
xt_register_target(struct xt_target*target)
{
intret, af = target->family;
……………………
list_add(&target->list,&xt[af].target);
……………………
returnret;
}
注册了以下的两个target后,当用iptables命令设置DNAT或则SNAT时,会将该target及参数组织成规则rule,组装成struct ipt_entry,即为规则体。
iptables –t nat –A POSTROUTING –s 192.168.0.0/24 –j SNAT –to 1.1.1.1
iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 80 -jDNAT --to 192.168.0.1
static struct xt_targetipt_snat_reg __read_mostly = {
.name = "SNAT",
.target = ipt_snat_target,
.targetsize = sizeof(structnf_nat_multi_range_compat),
.table = "nat",
.hooks = 1 << NF_INET_POST_ROUTING,
.checkentry = ipt_snat_checkentry,
.family = AF_INET,
};
static struct xt_target ipt_dnat_reg __read_mostly = {
.name = "DNAT",
.target = ipt_dnat_target,
.targetsize = sizeof(structnf_nat_multi_range_compat),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |(1 << NF_INET_LOCAL_OUT),
.checkentry = ipt_dnat_checkentry,
.family = AF_INET,
};
2.4钩子函数的执行,以nf_nat_in为例
nf_nat_in(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
unsignedint ret;
__be32daddr = ip_hdr(skb)->daddr;
ret=nf_nat_fn(hooknum, skb, in, out, okfn);
if(ret != NF_DROP && ret != NF_STOLEN &&
daddr != ip_hdr(skb)->daddr) {
dst_release(skb->dst);//该路由项为空,后面会进入路由系统进行选择路由
skb->dst= NULL;
}
returnret;
}
下面重点看nf_nat_fn()
2.5 target函数的执行
static unsigned int ipt_snat_target(structsk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
………………….
ct = nf_ct_get(skb, &ctinfo);
………………….
nf_nat_setup_info(ct,&mr->range[0], IP_NAT_MANIP_SRC);
主要是为新的连接建立连接跟踪记录
………………….
}