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

📄 ip_nat_core.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return ret;}static inline inthelper_cmp(const struct ip_nat_helper *helper,	   const struct ip_conntrack_tuple *tuple){	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);}/* Where to manip the reply packets (will be reverse manip). */static unsigned int opposite_hook[NF_IP_NUMHOOKS]= { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,    [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,    [NF_IP_LOCAL_OUT] = NF_IP_POST_ROUTING};unsigned intip_nat_setup_info(struct ip_conntrack *conntrack,		  const struct ip_nat_multi_range *mr,		  unsigned int hooknum){	struct ip_conntrack_tuple new_tuple, inv_tuple, reply;	struct ip_conntrack_tuple orig_tp;	struct ip_nat_info *info = &conntrack->nat.info;	MUST_BE_WRITE_LOCKED(&ip_nat_lock);	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING		     || hooknum == NF_IP_POST_ROUTING		     || hooknum == NF_IP_LOCAL_OUT);	IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);	/* What we've got will look like inverse of reply. Normally	   this is what is in the conntrack, except for prior	   manipulations (future optimization: if num_manips == 0,	   orig_tp =	   conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */	invert_tuplepr(&orig_tp,		       &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);#if 0	{	unsigned int i;	DEBUGP("Hook %u (%s), ", hooknum,	       HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");	DUMP_TUPLE(&orig_tp);	DEBUGP("Range %p: ", mr);	for (i = 0; i < mr->rangesize; i++) {		DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",		       i,		       (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)		       ? " MAP_IPS" : "",		       (mr->range[i].flags			& IP_NAT_RANGE_PROTO_SPECIFIED)		       ? " PROTO_SPECIFIED" : "",		       (mr->range[i].flags & IP_NAT_RANGE_FULL)		       ? " FULL" : "",		       NIPQUAD(mr->range[i].min_ip),		       NIPQUAD(mr->range[i].max_ip),		       mr->range[i].min.all,		       mr->range[i].max.all);	}	}#endif	do {		if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,				      hooknum)) {			DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",			       conntrack);			return NF_DROP;		}#if 0		DEBUGP("Hook %u (%s) %p\n", hooknum,		       HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",		       conntrack);		DEBUGP("Original: ");		DUMP_TUPLE(&orig_tp);		DEBUGP("New: ");		DUMP_TUPLE(&new_tuple);#endif		/* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):		   the original (A/B/C/D') and the mangled one (E/F/G/H').		   We're only allowed to work with the SRC per-proto		   part, so we create inverses of both to start, then		   derive the other fields we need.  */		/* Reply connection: simply invert the new tuple                   (G/H/E/F') */		invert_tuplepr(&reply, &new_tuple);		/* Alter conntrack table so it recognizes replies.                   If fail this race (reply tuple now used), repeat. */	} while (!ip_conntrack_alter_reply(conntrack, &reply));	/* FIXME: We can simply used existing conntrack reply tuple           here --RR */	/* Create inverse of original: C/D/A/B' */	invert_tuplepr(&inv_tuple, &orig_tp);	/* Has source changed?. */	if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {		/* In this direction, a source manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_ORIGINAL, hooknum,			   IP_NAT_MANIP_SRC, new_tuple.src });		IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);		/* In the reverse direction, a destination manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_REPLY, opposite_hook[hooknum],			   IP_NAT_MANIP_DST, orig_tp.src });		IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);	}	/* Has destination changed? */	if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {		/* In this direction, a destination manip */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_ORIGINAL, hooknum,			   IP_NAT_MANIP_DST, reply.src });		IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);		/* In the reverse direction, a source manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_REPLY, opposite_hook[hooknum],			   IP_NAT_MANIP_SRC, inv_tuple.src });		IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);	}	/* If there's a helper, assign it; based on new tuple. */	info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,				 &reply);	/* It's done. */	info->initialized |= (1 << HOOK2MANIP(hooknum));	return NF_ACCEPT;}void replace_in_hashes(struct ip_conntrack *conntrack,		       struct ip_nat_info *info){	/* Source has changed, so replace in hashes. */	unsigned int srchash		= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.src,			      conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.dst.protonum);	/* We place packet as seen OUTGOUNG in byips_proto hash           (ie. reverse dst and src of reply packet. */	unsigned int ipsprotohash		= hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.src.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.protonum);	IP_NF_ASSERT(info->bysource.conntrack == conntrack);	MUST_BE_WRITE_LOCKED(&ip_nat_lock);	list_del(&info->bysource.list);	list_del(&info->byipsproto.list);	list_prepend(&bysource[srchash], &info->bysource);	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);}void place_in_hashes(struct ip_conntrack *conntrack,		     struct ip_nat_info *info){	unsigned int srchash		= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.src,			      conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.dst.protonum);	/* We place packet as seen OUTGOUNG in byips_proto hash           (ie. reverse dst and src of reply packet. */	unsigned int ipsprotohash		= hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.src.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.protonum);	IP_NF_ASSERT(!info->bysource.conntrack);	MUST_BE_WRITE_LOCKED(&ip_nat_lock);	info->byipsproto.conntrack = conntrack;	info->bysource.conntrack = conntrack;	list_prepend(&bysource[srchash], &info->bysource);	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);}static voidmanip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,	  const struct ip_conntrack_manip *manip,	  enum ip_nat_manip_type maniptype,	  __u32 *nfcache){	*nfcache |= NFC_ALTERED;	find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);	if (maniptype == IP_NAT_MANIP_SRC) {		iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,						iph->check);		iph->saddr = manip->ip;	} else {		iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,						iph->check);		iph->daddr = manip->ip;	}#if 0	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)		DEBUGP("IP: checksum on packet bad.\n");	if (proto == IPPROTO_TCP) {		void *th = (u_int32_t *)iph + iph->ihl;		if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,				 csum_partial((char *)th, len-4*iph->ihl, 0)))			DEBUGP("TCP: checksum on packet bad\n");	}#endif}/* Do packet manipulations according to binding. */unsigned intdo_bindings(struct ip_conntrack *ct,	    enum ip_conntrack_info ctinfo,	    struct ip_nat_info *info,	    unsigned int hooknum,	    struct sk_buff **pskb){	unsigned int i;	struct ip_nat_helper *helper;	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);	/* Need nat lock to protect against modification, but neither	   conntrack (referenced) and helper (deleted with	   synchronize_bh()) can vanish. */	READ_LOCK(&ip_nat_lock);	for (i = 0; i < info->num_manips; i++) {		if (info->manips[i].direction == dir		    && info->manips[i].hooknum == hooknum) {			DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",			       *pskb,			       info->manips[i].maniptype == IP_NAT_MANIP_SRC			       ? "SRC" : "DST",			       NIPQUAD(info->manips[i].manip.ip),			       htons(info->manips[i].manip.u.all));			manip_pkt((*pskb)->nh.iph->protocol,				  (*pskb)->nh.iph,				  (*pskb)->len,				  &info->manips[i].manip,				  info->manips[i].maniptype,				  &(*pskb)->nfcache);		}	}	helper = info->helper;	READ_UNLOCK(&ip_nat_lock);	if (helper) {		/* Always defragged for helpers */		IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off			       & __constant_htons(IP_MF|IP_OFFSET)));		return helper->help(ct, info, ctinfo, hooknum, pskb);	} else return NF_ACCEPT;}unsigned inticmp_reply_translation(struct sk_buff *skb,		       struct ip_conntrack *conntrack,		       unsigned int hooknum,		       int dir){	struct iphdr *iph = skb->nh.iph;	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);	struct iphdr *inner = (struct iphdr *)(hdr + 1);	size_t datalen = skb->len - ((void *)inner - (void *)iph);	unsigned int i;	struct ip_nat_info *info = &conntrack->nat.info;	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));	/* Must be RELATED */	IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master		     == IP_CT_RELATED		     || skb->nfct - (struct ip_conntrack *)skb->nfct->master		     == 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 (hdr->type == ICMP_REDIRECT) {		/* Don't care about races here. */		if (info->initialized		    != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))		    || info->num_manips != 0)			return NF_DROP;	}	DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",	       skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");	/* Note: May not be from a NAT'd host, but probably safest to	   do translation always as if it came from the host itself	   (even though a "host unreachable" coming from the host	   itself is a bit wierd).	   More explanation: some people use NAT for anonymizing.	   Also, CERT recommends dropping all packets from private IP	   addresses (although ICMP errors from internal links with	   such addresses are not too uncommon, as Alan Cox points	   out) */	READ_LOCK(&ip_nat_lock);	for (i = 0; i < info->num_manips; i++) {		DEBUGP("icmp_reply: manip %u dir %s hook %u\n",		       i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?		       "ORIG" : "REPLY", info->manips[i].hooknum);		if (info->manips[i].direction != dir)			continue;		/* Mapping the inner packet is just like a normal		   packet, except it was never src/dst reversed, so		   where we would normally apply a dst manip, we apply		   a src, and vice versa. */		if (info->manips[i].hooknum == opposite_hook[hooknum]) {			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",			       info->manips[i].maniptype == IP_NAT_MANIP_SRC			       ? "DST" : "SRC",			       NIPQUAD(info->manips[i].manip.ip),			       ntohs(info->manips[i].manip.u.udp.port));			manip_pkt(inner->protocol, inner,				  skb->len - ((void *)inner - (void *)iph),				  &info->manips[i].manip,				  !info->manips[i].maniptype,				  &skb->nfcache);		/* Outer packet needs to have IP header NATed like                   it's a reply. */		} else if (info->manips[i].hooknum == hooknum) {			/* Use mapping to map outer packet: 0 give no                           per-proto mapping */			DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",			       info->manips[i].maniptype == IP_NAT_MANIP_SRC			       ? "SRC" : "DST",			       NIPQUAD(info->manips[i].manip.ip));			manip_pkt(0, iph, skb->len,				  &info->manips[i].manip,				  info->manips[i].maniptype,				  &skb->nfcache);		}	}	READ_UNLOCK(&ip_nat_lock);	/* Since we mangled inside ICMP packet, recalculate its	   checksum from scratch.  (Hence the handling of incorrect	   checksums in conntrack, so we don't accidentally fix one.)  */	hdr->checksum = 0;	hdr->checksum = ip_compute_csum((unsigned char *)hdr,					sizeof(*hdr) + datalen);	return NF_ACCEPT;}int ip_nat_helper_register(struct ip_nat_helper *me){	int ret = 0;	WRITE_LOCK(&ip_nat_lock);	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))		ret = -EBUSY;	else {		list_prepend(&helpers, me);		MOD_INC_USE_COUNT;	}	WRITE_UNLOCK(&ip_nat_lock);	return ret;}static intkill_helper(const struct ip_conntrack *i, void *helper){	int ret;	READ_LOCK(&ip_nat_lock);	ret = (i->nat.info.helper == helper);	READ_UNLOCK(&ip_nat_lock);	return ret;}void ip_nat_helper_unregister(struct ip_nat_helper *me){	WRITE_LOCK(&ip_nat_lock);	LIST_DELETE(&helpers, me);	WRITE_UNLOCK(&ip_nat_lock);	/* Someone could be still looking at the helper in a bh. */	br_write_lock_bh(BR_NETPROTO_LOCK);	br_write_unlock_bh(BR_NETPROTO_LOCK);	/* Find anything using it, and umm, kill them.  We can't turn	   them into normal connections: if we've adjusted SYNs, then	   they'll ackstorm.  So we just drop it.  We used to just	   bump module count when a connection existed, but that	   forces admins to gen fake RSTs or bounce box, either of	   which is just a long-winded way of making things	   worse. --RR */	ip_ct_selective_cleanup(kill_helper, me);	MOD_DEC_USE_COUNT;}int __init ip_nat_init(void){	size_t i;	/* Sew in builtin protocols. */	WRITE_LOCK(&ip_nat_lock);	list_append(&protos, &ip_nat_protocol_tcp);	list_append(&protos, &ip_nat_protocol_udp);	list_append(&protos, &ip_nat_protocol_icmp);	WRITE_UNLOCK(&ip_nat_lock);	for (i = 0; i < IP_NAT_HTABLE_SIZE; i++) {		INIT_LIST_HEAD(&bysource[i]);		INIT_LIST_HEAD(&byipsproto[i]);	}	/* FIXME: Man, this is a hack.  <SIGH> */	IP_NF_ASSERT(ip_conntrack_destroyed == NULL);	ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;	return 0;}void ip_nat_cleanup(void){	ip_conntrack_destroyed = NULL;}

⌨️ 快捷键说明

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