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

📄 ip_masq.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			write_lock(&__ip_masq_lock);#ifdef CONFIG_IP_MASQ_NREUSE		mst = __ip_masq_getbym(proto, maddr, mport);#else		mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);#endif		if (mst == NULL) {			if (atomic_read(free_ports_p) == 0) {				if (mflags & IP_MASQ_F_USER) 					write_unlock_bh(&__ip_masq_lock);				else					write_unlock(&__ip_masq_lock);				break;			}			atomic_dec(free_ports_p);			ip_masq_hash(ms);			if (mflags & IP_MASQ_F_USER) 				write_unlock_bh(&__ip_masq_lock);			else				write_unlock(&__ip_masq_lock);			ip_masq_bind_app(ms);			n_fails = 0;			atomic_inc(&ms->refcnt);			masq_set_state_timeout(ms, IP_MASQ_S_NONE);			return ms;		}		if (mflags & IP_MASQ_F_USER) 			write_unlock_bh(&__ip_masq_lock);		else			write_unlock(&__ip_masq_lock);		__ip_masq_put(mst);        }        if (++n_fails < 5)                IP_MASQ_ERR( "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",                       masq_proto_name(ms->protocol), 		       atomic_read(free_ports_p));mport_nono:        kfree_s(ms, sizeof(*ms));	sysctl_ip_always_defrag--;	MOD_DEC_USE_COUNT;        return NULL;}/* *	Get transport protocol data offset, check against size *	return: *		0  if other IP proto *		-1 if error */static __inline__ int proto_doff(unsigned proto, char *th, unsigned size){	int ret = -1;	switch (proto) {		case IPPROTO_ICMP:			if (size >= sizeof(struct icmphdr))				ret = sizeof(struct icmphdr);			break;		case IPPROTO_UDP:			if (size >= sizeof(struct udphdr))				ret = sizeof(struct udphdr);			break;		case IPPROTO_TCP:			/*			*	Is this case, this check _also_ avoids			*	touching an invalid pointer if 			*	size is invalid			*/			if (size >= sizeof(struct tcphdr)) {				ret = ((struct tcphdr*)th)->doff << 2;				if (ret > size) {					ret = -1 ;				}			}			break;		default:			/* 	Other proto: nothing to say, by now :) */			ret = 0;	}	if (ret < 0)		IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n",			proto, size);	return ret;}int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr){	struct sk_buff  *skb = *skb_p;	struct iphdr	*iph = skb->nh.iph;	union ip_masq_tphdr h;	struct ip_masq	*ms;	int		size;	/* 	 * 	doff holds transport protocol data offset	 *	csum holds its checksum	 *	csum_ok says if csum is valid	 */	int doff = 0;	int csum = 0;	int csum_ok = 0;	/*	 * We can only masquerade protocols with ports... and hack some ICMPs	 */	h.raw = (char*) iph + iph->ihl * 4;	size = ntohs(iph->tot_len) - (iph->ihl * 4);	doff = proto_doff(iph->protocol, h.raw, size);	if (doff <= 0) {		/*			 *	Output path: do not pass other IP protos nor		 *	invalid packets.		 */		return -1;	}	/* Lets determine our maddr now, shall we? */	if (maddr == 0) {		struct rtable *rt;		struct rtable *skb_rt = (struct rtable*)skb->dst;		struct device *skb_dev = skb_rt->u.dst.dev;		if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos)|RTO_CONN, skb_dev?skb_dev->ifindex:0)) {			/* Fallback on old method */			/* This really shouldn't happen... */			maddr = inet_select_addr(skb_dev, skb_rt->rt_gateway, RT_SCOPE_UNIVERSE);		} else {			/* Route lookup succeeded */			maddr = rt->rt_src;			ip_rt_put(rt);		}	}	switch (iph->protocol) {	case IPPROTO_ICMP:		return(ip_fw_masq_icmp(skb_p, maddr));	case IPPROTO_UDP:		if (h.uh->check == 0)			/* No UDP checksum */			break;	case IPPROTO_TCP:		/* Make sure packet is in the masq range */		IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n",				masq_proto_name(iph->protocol),				size);#ifdef CONFIG_IP_MASQ_DEBUG		if (ip_masq_get_debug_level() > 3) {			skb->ip_summed = CHECKSUM_NONE;		}#endif		/* Check that the checksum is OK */		switch (skb->ip_summed)		{			case CHECKSUM_NONE:			{				csum = csum_partial(h.raw + doff, size - doff, 0);				IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n",						masq_proto_name(iph->protocol),						csum);				skb->csum = csum_partial(h.raw , doff, csum);			}			case CHECKSUM_HW:				if (csum_tcpudp_magic(iph->saddr, iph->daddr, 						size, iph->protocol, skb->csum))				{					IP_MASQ_DEBUG(0, "Outgoing failed %s checksum from %d.%d.%d.%d (size=%d)!\n",					       masq_proto_name(iph->protocol),					       NIPQUAD(iph->saddr),					       size);					return -1;				}			default:				/* CHECKSUM_UNNECESSARY */		}		break;	default:		return -1;	}	/*	 *	Now hunt the list to see if we have an old entry	 */	/* h.raw = (char*) iph + iph->ihl * 4; */ 	IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",  		masq_proto_name(iph->protocol),  		ntohl(iph->saddr), ntohs(h.portp[0]),  		ntohl(iph->daddr), ntohs(h.portp[1]));        ms = ip_masq_out_get_iph(iph);        if (ms!=NULL) {                /*                 *	If sysctl !=0 and no pkt has been received yet                 *	in this tunnel and routing iface address has changed...                 *	 "You are welcome, diald".                 */                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {                        if (sysctl_ip_dynaddr > 1) {                                IP_MASQ_INFO( "ip_fw_masquerade(): change masq.addr from %d.%d.%d.%d to %d.%d.%d.%d\n",                                       NIPQUAD(ms->maddr),NIPQUAD(maddr));                        }			write_lock(&__ip_masq_lock);                        ip_masq_unhash(ms);                        ms->maddr = maddr;                        ip_masq_hash(ms);			write_unlock(&__ip_masq_lock);                }                		/*		 *      Set sport if not defined yet (e.g. ftp PASV).  Because		 *	masq entries are hashed on sport, unhash with old value		 *	and hash with new.		 */		if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {			write_lock(&__ip_masq_lock);						ip_masq_unhash(ms);			ms->flags &= ~IP_MASQ_F_NO_SPORT;			ms->sport = h.portp[0];			ip_masq_hash(ms);	/* hash on new sport */			write_unlock(&__ip_masq_lock);						IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",			       ntohs(ms->sport));		}		if (ms->flags & IP_MASQ_F_DLOOSE) {			/*			 *	update dest loose values			 */			ms->dport = h.portp[1];			ms->daddr = iph->daddr;		}        } else {		/*		 *	Nope, not found, create a new entry for it		 */#ifdef CONFIG_IP_MASQUERADE_MOD		if (!(ms = ip_masq_mod_out_create(skb, iph, maddr))) #endif			ms = ip_masq_new(iph->protocol,					maddr, 0,					iph->saddr, h.portp[0],					iph->daddr, h.portp[1],					0);                if (ms == NULL)			return -1; 	}	/* 	 * 	Call module's output update hook	 */#ifdef CONFIG_IP_MASQUERADE_MOD	ip_masq_mod_out_update(skb, iph, ms);#endif 	/* 	 *	Change the fragments origin 	 */ 	size = skb->len - (h.raw - skb->nh.raw);        /*         *	Set iph addr and port from ip_masq obj.         */ 	iph->saddr = ms->maddr; 	h.portp[0] = ms->mport;	/*	 *	Invalidate csum saving if tunnel has masq helper	 */	if (ms->app) 		csum_ok = 0; 	/* 	 *	Attempt ip_masq_app call.         *	will fix ip_masq and iph seq stuff 	 */        if (ip_masq_app_pkt_out(ms, skb_p, maddr) != 0)	{                /*                 *	skb has possibly changed, update pointers.                 */                skb = *skb_p;                iph = skb->nh.iph;		h.raw = (char*) iph + iph->ihl *4;                size = skb->len - (h.raw - skb->nh.raw);		/* doff should have not changed */        } 	/* 	 *	Adjust packet accordingly to protocol 	 */	/*	 *	Transport's payload partial csum	 */	if (!csum_ok) {		csum = csum_partial(h.raw + doff, size - doff, 0);	}	skb->csum = csum;	IP_MASQ_DEBUG(3, "O-pkt: %s size=%d O-datacsum=%d\n",			masq_proto_name(iph->protocol),			size,			csum);	/*	 * 	Protocol csum	 */	switch (iph->protocol) {		case IPPROTO_TCP:			h.th->check = 0;			h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 					size, iph->protocol, 					csum_partial(h.raw , doff, csum));			IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",					masq_proto_name(iph->protocol),					h.th->check,					(char*) & (h.th->check) - (char*) h.raw);			break;		case IPPROTO_UDP:			h.uh->check = 0;			h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 					size, iph->protocol, 					csum_partial(h.raw , doff, csum));			if (h.uh->check == 0) 				h.uh->check = 0xFFFF;			IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",					masq_proto_name(iph->protocol),					h.uh->check,					(char*) &(h.uh->check)- (char*) h.raw);			break;	}	ip_send_check(iph);  	IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",		ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));	masq_set_state(ms, 1, iph, h.portp);	ip_masq_put(ms);	return 0; }/* *	Restore original addresses and ports in the original IP *	datagram if the failing packet has been [de]masqueraded. *	This is ugly in the extreme.  We no longer have the original *	packet so we have to reconstruct it from the failing packet *	plus data in the masq tables.  The resulting "original data" *	should be good enough to tell the sender which session to *	throttle.  Relies on far too much knowledge of masq internals, *	there ought to be a better way - KAO 990303. * *	Moved here from icmp.c - JJC. *	Already known: type == ICMP_DEST_UNREACH, IPSKB_MASQUERADED *	skb->nh.iph points to original header. * *	Must try both OUT and IN tables; we could add a flag *	ala IPSKB_MASQUERADED to avoid 2nd tables lookup, but this is VERY *	unlike because routing makes mtu decision before reaching  *	ip_fw_masquerade(). *	 */int ip_fw_unmasq_icmp(struct sk_buff *skb) {	struct ip_masq *ms;	struct iphdr *iph = skb->nh.iph;	__u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);	/* 	 *	Always called from _bh context: use read_[un]lock()	 */	/*	 * 	Peek "out" table, this packet has bounced:	 *	out->in(frag_needed!)->OUT[icmp]	 *	 *	iph->daddr is IN host	 *	iph->saddr is OUT host	 */	read_lock(&__ip_masq_lock);	ms = __ip_masq_out_get(iph->protocol,			iph->daddr, portp[1],			iph->saddr, portp[0]);	read_unlock(&__ip_masq_lock);	if (ms) {		IP_MASQ_DEBUG(1, "Incoming frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n",			NIPQUAD(iph->daddr), NIPQUAD(ms->maddr));		iph->daddr = ms->maddr;		portp[1] = ms->mport;		__ip_masq_put(ms);		return 1;	}	/*	 * 	Peek "in" table	 *	in->out(frag_needed!)->IN[icmp]	 *	 *	iph->daddr is OUT host	 *	iph->saddr is MASQ host	 *	 */	read_lock(&__ip_masq_lock);	ms = __ip_masq_in_get(iph->protocol,			iph->daddr, portp[1],			iph->saddr, portp[0]);	read_unlock(&__ip_masq_lock);	if (ms) {		IP_MASQ_DEBUG(1, "Outgoing frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n",			NIPQUAD(iph->saddr), NIPQUAD(ms->saddr));		iph->saddr = ms->saddr;		portp[0] = ms->sport;		__ip_masq_put(ms);		return 1;	}	return 0;}/* *	Handle ICMP messages in forward direction. *	Find any that might be relevant, check against existing connections, *	forward to masqueraded host if relevant. *	Currently handles error types - unreachable, quench, ttl exceeded */int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr){        struct sk_buff 	*skb   = *skb_p; 	struct iphdr	*iph   = skb->nh.iph;	struct icmphdr  *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));	struct iphdr    *ciph;	/* The ip header contained within the ICMP */	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */	struct ip_masq	*ms;	unsigned short   len   = ntohs(iph->tot_len) - (iph->ihl * 4); 	IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n",	        icmph->type, ntohs(icmp_id(icmph)), 		ntohl(iph->saddr), ntohl(iph->daddr));#ifdef CONFIG_IP_MASQUERADE_ICMP			if ((icmph->type == ICMP_ECHO ) ||	    (icmph->type == ICMP_TIMESTAMP ) ||	    (icmph->type == ICMP_INFO_REQUEST ) ||	    (icmph->type == ICMP_ADDRESS )) {		IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX  id %d type %d\n",		       ntohl(iph->saddr),		       ntohl(iph->daddr),		       ntohs(icmp_id(icmph)),		       icmph->type);		ms = ip_masq_out_get(iph->protocol,				       iph->saddr,				       icmp_id(icmph),				       iph->daddr,				       icmp_hv_req(icmph));		if (ms == NULL) {			ms = ip_masq_new(iph->protocol,					 maddr, 0,					 iph->saddr, icmp_id(icmph),					 iph->daddr, icmp_hv_req(icmph),					 0);			if (ms == NULL)				return (-1);			IP_MASQ_DEBUG(1, "Created new icmp entry\n");		}		/* Rewrite source address */                                /*                 *	If sysctl !=0 and no pkt has been received yet                 *	in this tunnel and routing iface address has changed...                 *	 "You are welcome, diald".                 */                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {                        if (sysctl_ip_dynaddr > 1) {				IP_MASQ_INFO( "ip_fw_masq_icmp(): change masq.addr %d.%d.%d.%d to %d.%d.%d.%d",				       NIPQUAD(ms->maddr), NIPQUAD(maddr));			}			write_lock(&__ip_masq_lock);			                        ip_masq_unhash(ms);                        ms->maddr = maddr;                        ip_masq_hash(ms);

⌨️ 快捷键说明

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