⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nf_nat_core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
manip_pkt(u_int16_t proto,	  struct sk_buff *skb,	  unsigned int iphdroff,	  const struct nf_conntrack_tuple *target,	  enum nf_nat_manip_type maniptype){	struct iphdr *iph;	struct nf_nat_protocol *p;	if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))		return 0;	iph = (void *)skb->data + iphdroff;	/* Manipulate protcol part. */	/* rcu_read_lock()ed by nf_hook_slow */	p = __nf_nat_proto_find(proto);	if (!p->manip_pkt(skb, iphdroff, target, maniptype))		return 0;	iph = (void *)skb->data + iphdroff;	if (maniptype == IP_NAT_MANIP_SRC) {		nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);		iph->saddr = target->src.u3.ip;	} else {		nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);		iph->daddr = target->dst.u3.ip;	}	return 1;}/* Do packet manipulations according to nf_nat_setup_info. */unsigned int nf_nat_packet(struct nf_conn *ct,			   enum ip_conntrack_info ctinfo,			   unsigned int hooknum,			   struct sk_buff *skb){	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);	unsigned long statusbit;	enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);	if (mtype == IP_NAT_MANIP_SRC)		statusbit = IPS_SRC_NAT;	else		statusbit = IPS_DST_NAT;	/* Invert if this is reply dir. */	if (dir == IP_CT_DIR_REPLY)		statusbit ^= IPS_NAT_MASK;	/* Non-atomic: these bits don't change. */	if (ct->status & statusbit) {		struct nf_conntrack_tuple target;		/* We are aiming to look like inverse of other direction. */		nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);		if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype))			return NF_DROP;	}	return NF_ACCEPT;}EXPORT_SYMBOL_GPL(nf_nat_packet);/* Dir is direction ICMP is coming from (opposite to packet it contains) */int nf_nat_icmp_reply_translation(struct nf_conn *ct,				  enum ip_conntrack_info ctinfo,				  unsigned int hooknum,				  struct sk_buff *skb){	struct {		struct icmphdr icmp;		struct iphdr ip;	} *inside;	struct nf_conntrack_l4proto *l4proto;	struct nf_conntrack_tuple inner, target;	int hdrlen = ip_hdrlen(skb);	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);	unsigned long statusbit;	enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);	if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))		return 0;	inside = (void *)skb->data + ip_hdrlen(skb);	/* We're actually going to mangle it beyond trivial checksum	   adjustment, so make sure the current checksum is correct. */	if (nf_ip_checksum(skb, hooknum, hdrlen, 0))		return 0;	/* Must be RELATED */	NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||		     skb->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);	/* Redirects on non-null nats must be dropped, else they'll	   start talking to each other without our translation, and be	   confused... --RR */	if (inside->icmp.type == ICMP_REDIRECT) {		/* If NAT isn't finished, assume it and drop. */		if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)			return 0;		if (ct->status & IPS_NAT_MASK)			return 0;	}	pr_debug("icmp_reply_translation: translating error %p manip %u "		 "dir %s\n", skb, manip,		 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");	/* rcu_read_lock()ed by nf_hook_slow */	l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);	if (!nf_ct_get_tuple(skb,			     ip_hdrlen(skb) + sizeof(struct icmphdr),			     (ip_hdrlen(skb) +			      sizeof(struct icmphdr) + inside->ip.ihl * 4),			     (u_int16_t)AF_INET,			     inside->ip.protocol,			     &inner, l3proto, l4proto))		return 0;	/* Change inner back to look like incoming packet.  We do the	   opposite manip on this hook to normal, because it might not	   pass all hooks (locally-generated ICMP).  Consider incoming	   packet: PREROUTING (DST manip), routing produces ICMP, goes	   through POSTROUTING (which must correct the DST manip). */	if (!manip_pkt(inside->ip.protocol, skb,		       ip_hdrlen(skb) + sizeof(inside->icmp),		       &ct->tuplehash[!dir].tuple,		       !manip))		return 0;	if (skb->ip_summed != CHECKSUM_PARTIAL) {		/* Reloading "inside" here since manip_pkt inner. */		inside = (void *)skb->data + ip_hdrlen(skb);		inside->icmp.checksum = 0;		inside->icmp.checksum =			csum_fold(skb_checksum(skb, hdrlen,					       skb->len - hdrlen, 0));	}	/* Change outer to look the reply to an incoming packet	 * (proto 0 means don't invert per-proto part). */	if (manip == IP_NAT_MANIP_SRC)		statusbit = IPS_SRC_NAT;	else		statusbit = IPS_DST_NAT;	/* Invert if this is reply dir. */	if (dir == IP_CT_DIR_REPLY)		statusbit ^= IPS_NAT_MASK;	if (ct->status & statusbit) {		nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);		if (!manip_pkt(0, skb, 0, &target, manip))			return 0;	}	return 1;}EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);/* Protocol registration. */int nf_nat_protocol_register(struct nf_nat_protocol *proto){	int ret = 0;	write_lock_bh(&nf_nat_lock);	if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {		ret = -EBUSY;		goto out;	}	rcu_assign_pointer(nf_nat_protos[proto->protonum], proto); out:	write_unlock_bh(&nf_nat_lock);	return ret;}EXPORT_SYMBOL(nf_nat_protocol_register);/* Noone stores the protocol anywhere; simply delete it. */void nf_nat_protocol_unregister(struct nf_nat_protocol *proto){	write_lock_bh(&nf_nat_lock);	rcu_assign_pointer(nf_nat_protos[proto->protonum],			   &nf_nat_unknown_protocol);	write_unlock_bh(&nf_nat_lock);	synchronize_rcu();}EXPORT_SYMBOL(nf_nat_protocol_unregister);#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)intnf_nat_port_range_to_nlattr(struct sk_buff *skb,			    const struct nf_nat_range *range){	NLA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),		&range->min.tcp.port);	NLA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),		&range->max.tcp.port);	return 0;nla_put_failure:	return -1;}EXPORT_SYMBOL_GPL(nf_nat_port_nlattr_to_range);intnf_nat_port_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range){	int ret = 0;	/* we have to return whether we actually parsed something or not */	if (tb[CTA_PROTONAT_PORT_MIN]) {		ret = 1;		range->min.tcp.port =			*(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MIN]);	}	if (!tb[CTA_PROTONAT_PORT_MAX]) {		if (ret)			range->max.tcp.port = range->min.tcp.port;	} else {		ret = 1;		range->max.tcp.port =			*(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MAX]);	}	return ret;}EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nlattr);#endif/* Noone using conntrack by the time this called. */static void nf_nat_cleanup_conntrack(struct nf_conn *ct){	struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);	if (nat == NULL || nat->ct == NULL)		return;	NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);	write_lock_bh(&nf_nat_lock);	hlist_del(&nat->bysource);	nat->ct = NULL;	write_unlock_bh(&nf_nat_lock);}static void nf_nat_move_storage(struct nf_conn *conntrack, void *old){	struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT);	struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old;	struct nf_conn *ct = old_nat->ct;	if (!ct || !(ct->status & IPS_NAT_DONE_MASK))		return;	write_lock_bh(&nf_nat_lock);	hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);	new_nat->ct = ct;	write_unlock_bh(&nf_nat_lock);}static struct nf_ct_ext_type nat_extend __read_mostly = {	.len		= sizeof(struct nf_conn_nat),	.align		= __alignof__(struct nf_conn_nat),	.destroy	= nf_nat_cleanup_conntrack,	.move		= nf_nat_move_storage,	.id		= NF_CT_EXT_NAT,	.flags		= NF_CT_EXT_F_PREALLOC,};static int __init nf_nat_init(void){	size_t i;	int ret;	ret = nf_ct_extend_register(&nat_extend);	if (ret < 0) {		printk(KERN_ERR "nf_nat_core: Unable to register extension\n");		return ret;	}	/* Leave them the same for the moment. */	nf_nat_htable_size = nf_conntrack_htable_size;	bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,					 &nf_nat_vmalloced);	if (!bysource) {		ret = -ENOMEM;		goto cleanup_extend;	}	/* Sew in builtin protocols. */	write_lock_bh(&nf_nat_lock);	for (i = 0; i < MAX_IP_NAT_PROTO; i++)		rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);	rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);	rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);	rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);	write_unlock_bh(&nf_nat_lock);	for (i = 0; i < nf_nat_htable_size; i++) {		INIT_HLIST_HEAD(&bysource[i]);	}	/* Initialize fake conntrack so that NAT will skip it */	nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;	l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);	return 0; cleanup_extend:	nf_ct_extend_unregister(&nat_extend);	return ret;}/* Clear NAT section of all conntracks, in case we're loaded again. */static int clean_nat(struct nf_conn *i, void *data){	struct nf_conn_nat *nat = nfct_nat(i);	if (!nat)		return 0;	memset(nat, 0, sizeof(*nat));	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);	return 0;}static void __exit nf_nat_cleanup(void){	nf_ct_iterate_cleanup(&clean_nat, NULL);	synchronize_rcu();	nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);	nf_ct_l3proto_put(l3proto);	nf_ct_extend_unregister(&nat_extend);}MODULE_LICENSE("GPL");module_init(nf_nat_init);module_exit(nf_nat_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -