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

📄 ip_nat.c

📁 NAT协议完整源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))		return NULL;	*nflags = IPN_ICMPERR;	icmp = (icmphdr_t *)fin->fin_dp;	oip = (ip_t *)&icmp->icmp_ip;	if (oip->ip_p == IPPROTO_TCP)		flags = IPN_TCP;	else if (oip->ip_p == IPPROTO_UDP)		flags = IPN_UDP;	udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));	/*	 * Need to adjust ICMP header to include the real IP#'s and	 * port #'s.  Only apply a checksum change relative to the	 * IP address change as it will be modified again in ip_natout	 * for both address and port.  Two checksum changes are	 * necessary for the two header address changes.  Be careful	 * to only modify the checksum once for the port # and twice	 * for the IP#.	 */	/*	 * Step 1	 * Fix the IP addresses in the offending IP packet. You also need	 * to adjust the IP header checksum of that offending IP packet	 * and the ICMP checksum of the ICMP error message itself.	 *	 * Unfortunately, for UDP and TCP, the IP addresses are also contained	 * in the pseudo header that is used to compute the UDP resp. TCP	 * checksum. So, we must compensate that as well. Even worse, the	 * change in the UDP and TCP checksums require yet another	 * adjustment of the ICMP checksum of the ICMP error message.	 *	 * For the moment we forget about TCP, because that checksum is not	 * in the first 8 bytes, so it will not be available in most cases.	 */	if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {		sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));		in = nat->nat_inip;		oip->ip_src = in;	} else {		sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));		in = nat->nat_outip;		oip->ip_dst = in;	}	sum2 = LONG_SUM(ntohl(in.s_addr));	CALC_SUMD(sum1, sum2, sumd);	if (nat->nat_dir == NAT_OUTBOUND) {		/*		 * Fix IP checksum of the offending IP packet to adjust for		 * the change in the IP address.		 *		 * Normally, you would expect that the ICMP checksum of the 		 * ICMP error message needs to be adjusted as well for the		 * IP address change in oip.		 * However, this is a NOP, because the ICMP checksum is 		 * calculated over the complete ICMP packet, which includes the		 * changed oip IP addresses and oip->ip_sum. However, these 		 * two changes cancel each other out (if the delta for		 * the IP address is x, then the delta for ip_sum is minus x), 		 * so no change in the icmp_cksum is necessary.		 *		 * Be careful that nat_dir refers to the direction of the		 * offending IP packet (oip), not to its ICMP response (icmp)		 */		fix_datacksum(&oip->ip_sum, sumd);		/*		 * Fix UDP pseudo header checksum to compensate for the		 * IP address change.		 */		if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {			/*			 * The UDP checksum is optional, only adjust it 			 * if it has been set.			 */			sum1 = ntohs(udp->uh_sum);			fix_datacksum(&udp->uh_sum, sumd);			sum2 = ntohs(udp->uh_sum);			/*			 * Fix ICMP checksum to compensate the UDP 			 * checksum adjustment.			 */			CALC_SUMD(sum1, sum2, sumd);			sumd2 = sumd;		}#if 0		/*		 * Fix TCP pseudo header checksum to compensate for the 		 * IP address change. Before we can do the change, we		 * must make sure that oip is sufficient large to hold		 * the TCP checksum (normally it does not!).		 */		if (oip->ip_p == IPPROTO_TCP) {				}#endif	} else {		/*		 * Fix IP checksum of the offending IP packet to adjust for		 * the change in the IP address.		 *		 * Normally, you would expect that the ICMP checksum of the 		 * ICMP error message needs to be adjusted as well for the		 * IP address change in oip.		 * However, this is a NOP, because the ICMP checksum is 		 * calculated over the complete ICMP packet, which includes the		 * changed oip IP addresses and oip->ip_sum. However, these 		 * two changes cancel each other out (if the delta for		 * the IP address is x, then the delta for ip_sum is minus x), 		 * so no change in the icmp_cksum is necessary.		 *		 * Be careful that nat_dir refers to the direction of the		 * offending IP packet (oip), not to its ICMP response (icmp)		 */		fix_datacksum(&oip->ip_sum, sumd);/* XXX FV : without having looked at Solaris source code, it seems unlikely * that SOLARIS would compensate this in the kernel (a body of an IP packet  * in the data section of an ICMP packet). I have the feeling that this should * be unconditional, but I'm not in a position to check. */#if !SOLARIS && !defined(__sgi)		/*		 * Fix UDP pseudo header checksum to compensate for the		 * IP address change.		 */		if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {			/*			 * The UDP checksum is optional, only adjust it 			 * if it has been set 			 */			sum1 = ntohs(udp->uh_sum);			fix_datacksum(&udp->uh_sum, sumd);			sum2 = ntohs(udp->uh_sum);			/*			 * Fix ICMP checksum to compensate the UDP 			 * checksum adjustment.			 */			CALC_SUMD(sum1, sum2, sumd);			sumd2 = sumd;		}		#if 0		/* 		 * Fix TCP pseudo header checksum to compensate for the 		 * IP address change. Before we can do the change, we		 * must make sure that oip is sufficient large to hold		 * the TCP checksum (normally it does not!).		 */		if (oip->ip_p == IPPROTO_TCP) {				};#endif		#endif	}	if ((flags & IPN_TCPUDP) != 0) {		tcphdr_t *tcp;		/*		 * XXX - what if this is bogus hl and we go off the end ?		 * In this case, nat_icmpinlookup() will have returned NULL.		 */		tcp = (tcphdr_t *)udp;		/*		 * Step 2 :		 * For offending TCP/UDP IP packets, translate the ports as		 * well, based on the NAT specification. Of course such		 * a change must be reflected in the ICMP checksum as well.		 *		 * Advance notice : Now it becomes complicated :-)		 *		 * Since the port fields are part of the TCP/UDP checksum		 * of the offending IP packet, you need to adjust that checksum		 * as well... but, if you change, you must change the icmp		 * checksum *again*, to reflect that change.		 *		 * To further complicate: the TCP checksum is not in the first		 * 8 bytes of the offending ip packet, so it most likely is not		 * available (we might have to fix that if the encounter a		 * device that returns more than 8 data bytes on icmp error)		 */		if (nat->nat_oport == tcp->th_dport) {			if (tcp->th_sport != nat->nat_inport) {				/*				 * Fix ICMP checksum to compensate port				 * adjustment.				 */				sum1 = ntohs(tcp->th_sport);				sum2 = ntohs(nat->nat_inport);				CALC_SUMD(sum1, sum2, sumd);				sumd2 += sumd;				tcp->th_sport = nat->nat_inport;				/*				 * Fix udp checksum to compensate port				 * adjustment.  NOTE : the offending IP packet				 * flows the other direction compared to the				 * ICMP message.				 *				 * The UDP checksum is optional, only adjust				 * it if it has been set.				 */				if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {					sum1 = ntohs(udp->uh_sum);					fix_datacksum(&udp->uh_sum, sumd);					sum2 = ntohs(udp->uh_sum);					/*					 * Fix ICMP checksum to 					 * compensate UDP checksum 					 * adjustment.					 */					CALC_SUMD(sum1, sum2, sumd);					sumd2 += sumd;				}			}		} else {			if (tcp->th_dport != nat->nat_outport) {				/*				 * Fix ICMP checksum to compensate port				 * adjustment.				 */				sum1 = ntohs(tcp->th_dport);				sum2 = ntohs(nat->nat_outport);				CALC_SUMD(sum1, sum2, sumd);				sumd2 += sumd;				tcp->th_dport = nat->nat_outport;				/*				 * Fix udp checksum to compensate port				 * adjustment.   NOTE : the offending IP				 * packet flows the other direction compared				 * to the ICMP message.				 *				 * The UDP checksum is optional, only adjust				 * it if it has been set.				 */				if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {					sum1 = ntohs(udp->uh_sum);					fix_datacksum(&udp->uh_sum, sumd);					sum2 = ntohs(udp->uh_sum);					/*					 * Fix ICMP checksum to compensate					 * UDP checksum adjustment.					 */					CALC_SUMD(sum1, sum2, sumd);					sumd2 += sumd;				}			}		}		if (sumd2) {			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);			if (nat->nat_dir == NAT_OUTBOUND) {				fix_outcksum(&icmp->icmp_cksum, sumd2);			} else {				fix_incksum(&icmp->icmp_cksum, sumd2);			}		}	}	nat->nat_age = fr_defnaticmpage;	return nat;}/* * NB: these lookups don't lock access to the list, it assume it has already * been done! *//* * Lookup a nat entry based on the mapped destination ip address/port and * real source address/port.  We use this lookup when receiving a packet, * we're looking for a table entry, based on the destination address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw)void *ifp;register u_int flags, p;struct in_addr src , mapdst;u_32_t ports;int rw;{	register u_short sport, dport;	register nat_t *nat;	register int nflags;	register u_32_t dst;	u_int hv;	dst = mapdst.s_addr;	dport = ports >> 16;	sport = ports & 0xffff;	flags &= IPN_TCPUDP;	hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);	nat = nat_table[1][hv];	for (; nat; nat = nat->nat_hnext[1]) {		nflags = nat->nat_flags;		if ((!ifp || ifp == nat->nat_ifp) &&		    nat->nat_oip.s_addr == src.s_addr &&		    nat->nat_outip.s_addr == dst &&		    (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))		     || (p == nat->nat_p)) && (!flags ||		     (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&		      ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))			return nat;	}	if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))		return NULL;	if (!rw) {		RWLOCK_EXIT(&ipf_nat);	}	hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz);	if (!rw) {		WRITE_ENTER(&ipf_nat);	}	nat = nat_table[1][hv];	for (; nat; nat = nat->nat_hnext[1]) {		nflags = nat->nat_flags;		if (ifp && ifp != nat->nat_ifp)			continue;		if (!(nflags & IPN_TCPUDP))			continue;		if (!(nflags & FI_WILDP))			continue;		if (nat->nat_oip.s_addr != src.s_addr ||		    nat->nat_outip.s_addr != dst)			continue;		if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&		    ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {			nat_tabmove(nat, ports);			break;		}	}	if (!rw) {		MUTEX_DOWNGRADE(&ipf_nat);	}	return nat;}/* * This function is only called for TCP/UDP NAT table entries where the * original was placed in the table without hashing on the ports and we now * want to include hashing on port numbers. */static void nat_tabmove(nat, ports)nat_t *nat;u_32_t ports;{	register u_short sport, dport;	nat_t **natp;	u_int hv;	dport = ports >> 16;	sport = ports & 0xffff;	if (nat->nat_oport == dport) {		nat->nat_inport = sport;		nat->nat_outport = sport;	}	/*	 * Remove the NAT entry from the old location	 */	if (nat->nat_hnext[0])		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];	*nat->nat_phnext[0] = nat->nat_hnext[0];	if (nat->nat_hnext[1])		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];	*nat->nat_phnext[1] = nat->nat_hnext[1];	/*	 * Add into the NAT table in the new position	 */	hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, ipf_nattable_sz);	natp = &nat_table[0][hv];	if (*natp)		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];	nat->nat_phnext[0] = natp;	nat->nat_hnext[0] = *natp;	*natp = nat;	hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, ipf_nattable_sz);	natp = &nat_table[1][hv];	if (*natp)		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];	nat->nat_phnext[1] = natp;	nat->nat_hnext[1] = *natp;	*natp = nat;}/* * Lookup a nat entry based on the source 'real' ip address/port and * destination address/port.  We use this lookup when sending a packet out, * we're looking for a table entry, based on the source address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw)void *ifp;register u_int flags, p;struct in_addr src , dst;u_32_t ports;int rw;{	register u_short sport, dport;	register nat_t *nat;	register int nflags;	u_32_t srcip;	u_int hv;	sport = ports & 0xffff;	dport = ports >> 16;	flags &= IPN_TCPUDP;	srcip = src.s_addr;	hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);	nat = nat_table[0][hv];	for (; nat; nat = nat->nat_hnext[0]) {		nflags = nat->nat_flags;		if ((!ifp || ifp == nat->nat_ifp) &&		    nat->nat_inip.s_addr == srcip &&		    nat->nat_oip.s_addr == dst.s_addr &&		    (((p == 0) && (flags == (nflags & IPN_TCPUDP)))		     || (p == nat->nat_p)) && (!flags ||		     ((nat->nat_inport == sport || nflags & FI_W_SPORT) &&		      (nat->nat_oport == dport || nflags & FI_W_DPORT))))			return nat;	}	if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))		return NULL;	if (!rw) {		RWLOCK_EXIT(&ipf_nat);	}	hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);	if (!rw) {		WRITE_ENTER(&ipf_nat);	}	nat = nat_table[0][hv];	for (; nat; nat = nat->nat_hnext[0]) {		nflags = nat->nat_flags;		if (ifp && ifp != nat->nat_ifp)			continue;		if (!(nflags & IPN_TCPUDP))			continue;		if (!(nflags & FI_WILDP))			continue;		if ((nat->nat_inip.s_addr != srcip) ||		    (nat->nat_oip.s_addr != dst.s_addr))			continue;		if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) &&		    ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) {			nat_tabmove(nat, ports);			break;		}	}	if (!rw) {		MUTEX_DOWNGRADE(&ipf_nat);	}	return nat;}/* * Lookup the NAT tables to search for a matching redirect */nat_t *nat_lookupredir(np)register natlookup_t *np;{	u_32_t ports;	nat_t *nat;	ports = (np->nl_outport << 16) | np->nl_inport;	/*	 * If nl_inip is non null, this is a lookup based on the real	 * ip address. Else, we use the fake.	 */	if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip,				 np->nl_outip, ports, 0))) {		np->nl_realip = nat->nat_outip;		np->nl_realport = nat->nat_outport;	}	return nat;}static int nat_match(fin, np, ip)fr_info_t *fin;ipnat_t *np;ip_t *ip;{	frtuc_t *ft;	if (ip->ip_v != 4)		return 0;	if (np->in_p && ip->ip_p != np->in_p)		return 0;	if (fin->fin_out) {		if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))			return 0;		if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip)		    ^ ((np->in_flags & IPN_NOTSRC) != 0))			return 0;		if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip)		    ^ ((np->in_flags & IPN_NOTDST) != 0))			return 0;	} else {		if (!(np->in_redir & NAT_REDIRECT))			return 0;		if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip)		    ^ ((np->in_flags & IPN_NOTSRC) != 0))			return 0;		if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip)		    ^ ((np->in_flags & IPN_NOTDST) != 0))			return 0;	}	ft = &np->in_tuc;	if (!(fin->fin_fi.fi_fl & FI_TCPUDP) ||

⌨️ 快捷键说明

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