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

📄 ip_nat.c

📁 NAT协议完整源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	    (fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) {		if (ft->ftu_scmp || ft->ftu_dcmp)			return 0;		return 1;	}	return fr_tcpudpchk(ft, fin);}/* * Packets going out on the external interface go through this. * Here, the source address requires alteration, if anything. */int ip_natout(ip, fin)ip_t *ip;fr_info_t *fin;{	register ipnat_t *np = NULL;	register u_32_t ipa;	tcphdr_t *tcp = NULL;	u_short sport = 0, dport = 0, *csump = NULL;	struct ifnet *ifp;	int natadd = 1;	frentry_t *fr;	u_int nflags = 0, hv, msk;	u_32_t iph;	nat_t *nat;	int i;	if (nat_list == NULL || (fr_nat_lock))		return 0;	if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&	    fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)		ifp = fr->fr_tif.fd_ifp;	else		ifp = fin->fin_ifp;	if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) {		if (ip->ip_p == IPPROTO_TCP)			nflags = IPN_TCP;		else if (ip->ip_p == IPPROTO_UDP)			nflags = IPN_UDP;		if ((nflags & IPN_TCPUDP)) {			tcp = (tcphdr_t *)fin->fin_dp;			sport = tcp->th_sport;			dport = tcp->th_dport;		}	}	ipa = ip->ip_src.s_addr;	READ_ENTER(&ipf_nat);	if ((ip->ip_p == IPPROTO_ICMP) &&	    (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND)))		;	else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&	    (nat = ipfr_nat_knownfrag(ip, fin)))		natadd = 0;	else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p,				      ip->ip_src, ip->ip_dst,				      (dport << 16) | sport, 0))) {		nflags = nat->nat_flags;		if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {			if ((nflags & FI_W_SPORT) &&			    (nat->nat_inport != sport))				nat->nat_inport = sport;			else if ((nflags & FI_W_DPORT) &&				 (nat->nat_oport != dport))				nat->nat_oport = dport;			if (nat->nat_outport == 0)				nat->nat_outport = sport;			nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);			nflags = nat->nat_flags;			nat_stats.ns_wilds--;		}	} else {		RWLOCK_EXIT(&ipf_nat);		WRITE_ENTER(&ipf_nat);		/*		 * If there is no current entry in the nat table for this IP#,		 * create one for it (if there is a matching rule).		 */		msk = 0xffffffff;		i = 32;maskloop:		iph = ipa & htonl(msk);		hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);		for (np = nat_rules[hv]; np; np = np->in_mnext)		{			if ((np->in_ifp && (np->in_ifp != ifp)) ||			    !np->in_space)				continue;			if ((np->in_flags & IPN_RF) &&			    !(np->in_flags & nflags))				continue;			if (np->in_flags & IPN_FILTER) {				if (!nat_match(fin, np, ip))					continue;			} else if ((ipa & np->in_inmsk) != np->in_inip)				continue;			if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) {				if (*np->in_plabel && !appr_ok(ip, tcp, np))					continue;				/*				 * If it's a redirection, then we don't want to				 * create new outgoing port stuff.				 * Redirections are only for incoming				 * connections.				 */				if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))					continue;				if ((nat = nat_new(np, ip, fin, (u_int)nflags,						    NAT_OUTBOUND))) {					np->in_hits++;					break;				}			}		}		if ((np == NULL) && (i > 0)) {			do {				i--;				msk <<= 1;			} while ((i >= 0) && ((nat_masks & (1 << i)) == 0));			if (i >= 0)				goto maskloop;		}		MUTEX_DOWNGRADE(&ipf_nat);	}	/*	 * NOTE: ipf_nat must now only be held as a read lock	 */	if (nat) {		np = nat->nat_ptr;		if (natadd && fin->fin_fi.fi_fl & FI_FRAG)			ipfr_nat_newfrag(ip, fin, 0, nat);		MUTEX_ENTER(&nat->nat_lock);		nat->nat_age = fr_defnatage;		nat->nat_bytes += ip->ip_len;		nat->nat_pkts++;		MUTEX_EXIT(&nat->nat_lock);		/*		 * Fix up checksums, not by recalculating them, but		 * simply computing adjustments.		 */		if (nflags == IPN_ICMPERR) {			u_32_t s1, s2, sumd;			s1 = LONG_SUM(ntohl(ip->ip_src.s_addr));			s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));			CALC_SUMD(s1, s2, sumd);			if (nat->nat_dir == NAT_OUTBOUND)				fix_incksum(&ip->ip_sum, sumd);			else				fix_outcksum(&ip->ip_sum, sumd);		}#if SOLARIS || defined(__sgi)		else {			if (nat->nat_dir == NAT_OUTBOUND)				fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);			else				fix_incksum(&ip->ip_sum, nat->nat_ipsumd);		}#endif		ip->ip_src = nat->nat_outip;		if (!(ip->ip_off & IP_OFFMASK) &&		    !(fin->fin_fi.fi_fl & FI_SHORT)) {			if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {				tcp->th_sport = nat->nat_outport;				fin->fin_data[0] = ntohs(tcp->th_sport);			}			if (ip->ip_p == IPPROTO_TCP) {				csump = &tcp->th_sum;				MUTEX_ENTER(&nat->nat_lock);				fr_tcp_age(&nat->nat_age,					   nat->nat_tcpstate, fin, 1);				if (nat->nat_age < fr_defnaticmpage)					nat->nat_age = fr_defnaticmpage;#ifdef LARGE_NAT				else if (nat->nat_age > fr_defnatage)					nat->nat_age = fr_defnatage;#endif				/*				 * Increase this because we may have				 * "keep state" following this too and				 * packet storms can occur if this is				 * removed too quickly.				 */				if (nat->nat_age == fr_tcpclosed)					nat->nat_age = fr_tcplastack;				MUTEX_EXIT(&nat->nat_lock);			} else if (ip->ip_p == IPPROTO_UDP) {				udphdr_t *udp = (udphdr_t *)tcp;				if (udp->uh_sum)					csump = &udp->uh_sum;			} else if (ip->ip_p == IPPROTO_ICMP) {				nat->nat_age = fr_defnaticmpage;			}			if (csump) {				if (nat->nat_dir == NAT_OUTBOUND)					fix_outcksum(csump, nat->nat_sumd[1]);				else					fix_incksum(csump, nat->nat_sumd[1]);			}		}		if ((np->in_apr != NULL) && (np->in_dport == 0 ||		     (tcp != NULL && dport == np->in_dport))) {			i = appr_check(ip, fin, nat);			if (i == 0)				i = 1;		} else			i = 1;		ATOMIC_INCL(nat_stats.ns_mapped[1]);		RWLOCK_EXIT(&ipf_nat);	/* READ */		return i;	}	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */	return 0;}/* * Packets coming in from the external interface go through this. * Here, the destination address requires alteration, if anything. */int ip_natin(ip, fin)ip_t *ip;fr_info_t *fin;{	register struct in_addr src;	register struct in_addr in;	register ipnat_t *np;	u_int nflags = 0, natadd = 1, hv, msk;	struct ifnet *ifp = fin->fin_ifp;	tcphdr_t *tcp = NULL;	u_short sport = 0, dport = 0, *csump = NULL;	nat_t *nat;	u_32_t iph;	int i;	if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock))		return 0;	if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) {		if (ip->ip_p == IPPROTO_TCP)			nflags = IPN_TCP;		else if (ip->ip_p == IPPROTO_UDP)			nflags = IPN_UDP;		if ((nflags & IPN_TCPUDP)) {			tcp = (tcphdr_t *)fin->fin_dp;			dport = tcp->th_dport;			sport = tcp->th_sport;		}	}	in = ip->ip_dst;	/* make sure the source address is to be redirected */	src = ip->ip_src;	READ_ENTER(&ipf_nat);	if ((ip->ip_p == IPPROTO_ICMP) &&	    (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND)))		;	else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&		 (nat = ipfr_nat_knownfrag(ip, fin)))		natadd = 0;	else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p,				     ip->ip_src, in, (dport << 16) | sport,				     0))) {		nflags = nat->nat_flags;		if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {			if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT))				nat->nat_oport = sport;			else if ((nat->nat_outport != dport) &&				 (nflags & FI_W_SPORT))				nat->nat_outport = dport;			nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);			nflags = nat->nat_flags;			nat_stats.ns_wilds--;		}	} else {		RWLOCK_EXIT(&ipf_nat);		WRITE_ENTER(&ipf_nat);		/*		 * If there is no current entry in the nat table for this IP#,		 * create one for it (if there is a matching rule).		 */		msk = 0xffffffff;		i = 32;maskloop:		iph = in.s_addr & htonl(msk);		hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);		for (np = rdr_rules[hv]; np; np = np->in_rnext) {			if ((np->in_ifp && (np->in_ifp != ifp)) ||			    (np->in_p && (np->in_p != ip->ip_p)) ||			    (np->in_flags && !(nflags & np->in_flags)))				continue;			if (np->in_flags & IPN_FILTER) {				if (!nat_match(fin, np, ip))					continue;			} else if ((in.s_addr & np->in_outmsk) != np->in_outip)				continue;			if ((np->in_redir & NAT_REDIRECT) &&			    (!np->in_pmin || (np->in_flags & IPN_FILTER) ||			     ((ntohs(np->in_pmax) >= ntohs(dport)) &&			      (ntohs(dport) >= ntohs(np->in_pmin)))))				if ((nat = nat_new(np, ip, fin, nflags,						    NAT_INBOUND))) {					np->in_hits++;					break;				}		}		if ((np == NULL) && (i > 0)) {			do {				i--;				msk <<= 1;			} while ((i >= 0) && ((rdr_masks & (1 << i)) == 0));			if (i >= 0)				goto maskloop;		}		MUTEX_DOWNGRADE(&ipf_nat);	}	/*	 * NOTE: ipf_nat must now only be held as a read lock	 */	if (nat) {		np = nat->nat_ptr;		fin->fin_fr = nat->nat_fr;		if (natadd && fin->fin_fi.fi_fl & FI_FRAG)			ipfr_nat_newfrag(ip, fin, 0, nat);		if ((np->in_apr != NULL) && (np->in_dport == 0 ||		    (tcp != NULL && sport == np->in_dport))) {			i = appr_check(ip, fin, nat);			if (i == -1) {				RWLOCK_EXIT(&ipf_nat);				return i;			}		}		MUTEX_ENTER(&nat->nat_lock);		if (nflags != IPN_ICMPERR)			nat->nat_age = fr_defnatage;		nat->nat_bytes += ip->ip_len;		nat->nat_pkts++;		MUTEX_EXIT(&nat->nat_lock);		ip->ip_dst = nat->nat_inip;		fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;		/*		 * Fix up checksums, not by recalculating them, but		 * simply computing adjustments.		 */#if SOLARIS || defined(__sgi)		if (nat->nat_dir == NAT_OUTBOUND)			fix_incksum(&ip->ip_sum, nat->nat_ipsumd);		else			fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);#endif		if (!(ip->ip_off & IP_OFFMASK) &&		    !(fin->fin_fi.fi_fl & FI_SHORT)) {			if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {				tcp->th_dport = nat->nat_inport;				fin->fin_data[1] = ntohs(tcp->th_dport);			}			if (ip->ip_p == IPPROTO_TCP) {				csump = &tcp->th_sum;				MUTEX_ENTER(&nat->nat_lock);				fr_tcp_age(&nat->nat_age,					   nat->nat_tcpstate, fin, 0);				if (nat->nat_age < fr_defnaticmpage)					nat->nat_age = fr_defnaticmpage;#ifdef LARGE_NAT				else if (nat->nat_age > fr_defnatage)					nat->nat_age = fr_defnatage;#endif				/*				 * Increase this because we may have				 * "keep state" following this too and				 * packet storms can occur if this is				 * removed too quickly.				 */				if (nat->nat_age == fr_tcpclosed)					nat->nat_age = fr_tcplastack;				MUTEX_EXIT(&nat->nat_lock);			} else if (ip->ip_p == IPPROTO_UDP) {				udphdr_t *udp = (udphdr_t *)tcp;				if (udp->uh_sum)					csump = &udp->uh_sum;			} else if (ip->ip_p == IPPROTO_ICMP) {				nat->nat_age = fr_defnaticmpage;			}			if (csump) {				if (nat->nat_dir == NAT_OUTBOUND)					fix_incksum(csump, nat->nat_sumd[0]);				else					fix_outcksum(csump, nat->nat_sumd[0]);			}		}		ATOMIC_INCL(nat_stats.ns_mapped[0]);		RWLOCK_EXIT(&ipf_nat);			/* READ */		return 1;	}	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */	return 0;}/* * Free all memory used by NAT structures allocated at runtime. */void ip_natunload(){	WRITE_ENTER(&ipf_nat);	(void) nat_clearlist();	(void) nat_flushtable();	RWLOCK_EXIT(&ipf_nat);	if (nat_table[0] != NULL) {		KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz);		nat_table[0] = NULL;	}	if (nat_table[1] != NULL) {		KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz);		nat_table[1] = NULL;	}	if (nat_rules != NULL) {		KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz);		nat_rules = NULL;	}	if (rdr_rules != NULL) {		KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz);		rdr_rules = NULL;	}	if (maptable != NULL) {		KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);		maptable = NULL;	}}/* * Slowly expire held state for NAT entries.  Timeouts are set in * expectation of this being called twice per second. */void ip_natexpire(){	register struct nat *nat, **natp;#if defined(_KERNEL) && !SOLARIS	int s;#endif	SPL_NET(s);	WRITE_ENTER(&ipf_nat);	for (natp = &nat_instances; (nat = *natp); ) {		nat->nat_age--;		if (nat->nat_age) {			natp = &nat->nat_next;			continue;		}		*natp = nat->nat_next;#ifdef	IPFILTER_LOG		nat_log(nat, NL_EXPIRE);#endif		nat_delete(nat);		nat_stats.ns_expire++;	}	RWLOCK_EXIT(&ipf_nat);	SPL_X(s);}/* */void ip_natsync(ifp)void *ifp;{	register ipnat_t *n;	register nat_t *nat;	register u_32_t sum1, sum2, sumd;	struct in_addr in;	ipnat_t *np;	void *ifp2;#if defined(_KERNEL) && !SOLARIS	int s;#endif	/*	 * Change IP addresses for NAT sessions for any protocol except TCP	 * since it will break the TCP connection anyway.	 */	SPL_NET(s);	WRITE_ENTER(&ipf_nat);	for (nat = nat_instances; nat; nat = nat->nat_next)		if (((ifp == NULL) || (ifp == nat->nat_ifp)) &&		    !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) &&		    (np->in_outmsk == 0xffffffff) && !np->in_nip) {			ifp2 = nat->nat_ifp;			/*			 * Change the map-to address to be the same as the			 * new one.			 */			sum1 = nat->nat_outip.s_addr;			if (fr_ifpaddr(4, ifp2, &in) != -1)				nat->nat_outip = in;			sum2 = nat->nat_outip.s_addr;			if (sum1 == sum2)				continue;			/*			 * Readjust the checksum adjustment to take into			 * account the new IP#.			 */			CALC_SUMD(sum1, sum2, sumd);			/* XXX - dont change for TCP when solaris does			 * hardware checksumming.			 */			sumd += nat->nat_sumd[0];			nat->nat_sumd[0] = (sumd & 0

⌨️ 快捷键说明

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