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

📄 ip_nat.c

📁 NAT协议完整源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		j++;	}	nat_stats.ns_inuse = 0;	return j;}/* * nat_clearlist - delete all rules in the active NAT mapping list. */static int nat_clearlist(){	register ipnat_t *n, **np = &nat_list;	int i = 0;	if (nat_rules != NULL)		bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz);	if (rdr_rules != NULL)		bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz);	while ((n = *np)) {		*np = n->in_next;		if (!n->in_use) {			if (n->in_apr)				appr_free(n->in_apr);			KFREE(n);			nat_stats.ns_rules--;		} else {			n->in_flags |= IPN_DELETE;			n->in_next = NULL;		}		i++;	}	nat_masks = 0;	rdr_masks = 0;	return i;}/* * Create a new NAT table entry. * NOTE: assumes write lock on ipf_nat has been obtained already. */nat_t *nat_new(np, ip, fin, flags, direction)ipnat_t *np;ip_t *ip;fr_info_t *fin;u_int flags;int direction;{	register u_32_t sum1, sum2, sumd, l;	u_short port = 0, sport = 0, dport = 0, nport = 0;	struct in_addr in, inb;	tcphdr_t *tcp = NULL;	hostmap_t *hm = NULL;	nat_t *nat, *natl;	u_short nflags;#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)	qif_t *qf = fin->fin_qif;#endif	nflags = flags & np->in_flags;	if (flags & IPN_TCPUDP) {		tcp = (tcphdr_t *)fin->fin_dp;		sport = tcp->th_sport;		dport = tcp->th_dport;	}	/* Give me a new nat */	KMALLOC(nat, nat_t *);	if (nat == NULL) {		nat_stats.ns_memfail++;		return NULL;	}	bzero((char *)nat, sizeof(*nat));	nat->nat_flags = flags;	if (flags & FI_WILDP)		nat_stats.ns_wilds++;	/*	 * Search the current table for a match.	 */	if (direction == NAT_OUTBOUND) {		/*		 * Values at which the search for a free resouce starts.		 */		u_32_t st_ip;		u_short st_port;		/*		 * If it's an outbound packet which doesn't match any existing		 * record, then create a new port		 */		l = 0;		st_ip = np->in_nip;		st_port = np->in_pnext;		do {			port = 0;			in.s_addr = htonl(np->in_nip);			if (l == 0) {				/*				 * Check to see if there is an existing NAT				 * setup for this IP address pair.				 */				hm = nat_hostmap(np, ip->ip_src, in);				if (hm != NULL)					in.s_addr = hm->hm_mapip.s_addr;			} else if ((l == 1) && (hm != NULL)) {				nat_hostmapdel(hm);				hm = NULL;			}			in.s_addr = ntohl(in.s_addr);			nat->nat_hm = hm;			if ((np->in_outmsk == 0xffffffff) &&			    (np->in_pnext == 0)) {				if (l > 0)					goto badnat;			}			if (np->in_redir & NAT_MAPBLK) {				if ((l >= np->in_ppip) || ((l > 0) &&				     !(flags & IPN_TCPUDP)))					goto badnat;				/*				 * map-block - Calculate destination address.				 */				in.s_addr = ntohl(ip->ip_src.s_addr);				in.s_addr &= ntohl(~np->in_inmsk);				inb.s_addr = in.s_addr;				in.s_addr /= np->in_ippip;				in.s_addr &= ntohl(~np->in_outmsk);				in.s_addr += ntohl(np->in_outip);				/*				 * Calculate destination port.				 */				if ((flags & IPN_TCPUDP) &&				    (np->in_ppip != 0)) {					port = ntohs(sport) + l;					port %= np->in_ppip;					port += np->in_ppip *						(inb.s_addr % np->in_ippip);					port += MAPBLK_MINPORT;					port = htons(port);				}			} else if (!np->in_outip &&				   (np->in_outmsk == 0xffffffff)) {				/*				 * 0/32 - use the interface's IP address.				 */				if ((l > 0) ||				    fr_ifpaddr(4, fin->fin_ifp, &in) == -1)					goto badnat;				in.s_addr = ntohl(in.s_addr);			} else if (!np->in_outip && !np->in_outmsk) {				/*				 * 0/0 - use the original source address/port.				 */				if (l > 0)					goto badnat;				in.s_addr = ntohl(ip->ip_src.s_addr);			} else if ((np->in_outmsk != 0xffffffff) &&				   (np->in_pnext == 0) &&				   ((l > 0) || (hm == NULL)))				np->in_nip++;			natl = NULL;			if ((nflags & IPN_TCPUDP) &&			    ((np->in_redir & NAT_MAPBLK) == 0) &&			    (np->in_flags & IPN_AUTOPORTMAP)) {				if ((l > 0) && (l % np->in_ppip == 0)) {					if (l > np->in_space) {						goto badnat;					} else if ((l > np->in_ppip) &&						   np->in_outmsk != 0xffffffff)						np->in_nip++;				}				if (np->in_ppip != 0) {					port = ntohs(sport);					port += (l % np->in_ppip);					port %= np->in_ppip;					port += np->in_ppip *						(ntohl(ip->ip_src.s_addr) %						 np->in_ippip);					port += MAPBLK_MINPORT;					port = htons(port);				}			} else if (((np->in_redir & NAT_MAPBLK) == 0) &&				   (nflags & IPN_TCPUDP) &&				   (np->in_pnext != 0)) {				port = htons(np->in_pnext++);				if (np->in_pnext > ntohs(np->in_pmax)) {					np->in_pnext = ntohs(np->in_pmin);					if (np->in_outmsk != 0xffffffff)						np->in_nip++;				}			}			if (np->in_flags & IPN_IPRANGE) {				if (np->in_nip > ntohl(np->in_outmsk))					np->in_nip = ntohl(np->in_outip);			} else {				if ((np->in_outmsk != 0xffffffff) &&				    ((np->in_nip + 1) & ntohl(np->in_outmsk)) >				    ntohl(np->in_outip))					np->in_nip = ntohl(np->in_outip) + 1;			}			if (!port && (flags & IPN_TCPUDP))				port = sport;			/*			 * Here we do a lookup of the connection as seen from			 * the outside.  If an IP# pair already exists, try			 * again.  So if you have A->B becomes C->B, you can			 * also have D->E become C->E but not D->B causing			 * another C->B.  Also take protocol and ports into			 * account when determining whether a pre-existing			 * NAT setup will cause an external conflict where			 * this is appropriate.			 */			inb.s_addr = htonl(in.s_addr);			natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP,					    (u_int)ip->ip_p, ip->ip_dst, inb,					    (port << 16) | dport, 1);			/*			 * Has the search wrapped around and come back to the			 * start ?			 */			if ((natl != NULL) &&			    (np->in_pnext != 0) && (st_port == np->in_pnext) &&			    (np->in_nip != 0) && (st_ip == np->in_nip))				goto badnat;			l++;		} while (natl != NULL);		if (np->in_space > 0)			np->in_space--;		/* Setup the NAT table */		nat->nat_inip = ip->ip_src;		nat->nat_outip.s_addr = htonl(in.s_addr);		nat->nat_oip = ip->ip_dst;		if (nat->nat_hm == NULL)			nat->nat_hm = nat_hostmap(np, ip->ip_src,						  nat->nat_outip);		sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport);		sum2 = LONG_SUM(in.s_addr) + ntohs(port);		if (flags & IPN_TCPUDP) {			nat->nat_inport = sport;			nat->nat_outport = port;	/* sport */			nat->nat_oport = dport;		}	} else {		/*		 * Otherwise, it's an inbound packet. Most likely, we don't		 * want to rewrite source ports and source addresses. Instead,		 * we want to rewrite to a fixed internal address and fixed		 * internal port.		 */		if (np->in_flags & IPN_SPLIT) {			in.s_addr = np->in_nip;			if (np->in_inip == htonl(in.s_addr))				np->in_nip = ntohl(np->in_inmsk);			else {				np->in_nip = ntohl(np->in_inip);				if (np->in_flags & IPN_ROUNDR) {					nat_delrdr(np);					nat_addrdr(np);				}			}		} else {			in.s_addr = ntohl(np->in_inip);			if (np->in_flags & IPN_ROUNDR) {				nat_delrdr(np);				nat_addrdr(np);			}		}		if (!np->in_pnext)			nport = dport;		else {			/*			 * Whilst not optimized for the case where			 * pmin == pmax, the gain is not significant.			 */			nport = ntohs(dport) - ntohs(np->in_pmin) +				ntohs(np->in_pnext);			nport = htons(nport);		}		/*		 * When the redirect-to address is set to 0.0.0.0, just		 * assume a blank `forwarding' of the packet.  We don't		 * setup any translation for this either.		 */		if (in.s_addr == 0) {			if (nport == dport)				goto badnat;			in.s_addr = ntohl(ip->ip_dst.s_addr);		}		nat->nat_inip.s_addr = htonl(in.s_addr);		nat->nat_outip = ip->ip_dst;		nat->nat_oip = ip->ip_src;		sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport);		sum2 = LONG_SUM(in.s_addr) + ntohs(nport);		if (flags & IPN_TCPUDP) {			nat->nat_inport = nport;			nat->nat_outport = dport;			nat->nat_oport = sport;		}	}	CALC_SUMD(sum1, sum2, sumd);	nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)	if ((flags == IPN_TCP) && dohwcksum &&	    (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {		if (direction == NAT_OUTBOUND)			sum1 = LONG_SUM(ntohl(in.s_addr));		else			sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));		sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr));		sum1 += 30;		sum1 = (sum1 & 0xffff) + (sum1 >> 16);		nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff);	} else#endif		nat->nat_sumd[1] = nat->nat_sumd[0];	if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {		if (direction == NAT_OUTBOUND)			sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));		else			sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr));		sum2 = LONG_SUM(in.s_addr);		CALC_SUMD(sum1, sum2, sumd);		nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);	} else		nat->nat_ipsumd = nat->nat_sumd[0];	in.s_addr = htonl(in.s_addr);#ifdef  _KERNEL	strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ);#endif	nat_insert(nat);	nat->nat_dir = direction;	nat->nat_ifp = fin->fin_ifp;	nat->nat_ptr = np;	nat->nat_p = ip->ip_p;	nat->nat_bytes = 0;	nat->nat_pkts = 0;	nat->nat_fr = fin->fin_fr;	if (nat->nat_fr != NULL) {		ATOMIC_INC32(nat->nat_fr->fr_ref);	}	if (direction == NAT_OUTBOUND) {		if (flags & IPN_TCPUDP)			tcp->th_sport = port;	} else {		if (flags & IPN_TCPUDP)			tcp->th_dport = nport;	}	np->in_use++;#ifdef	IPFILTER_LOG	nat_log(nat, (u_int)np->in_redir);#endif	return nat;badnat:	nat_stats.ns_badnat++;	if ((hm = nat->nat_hm) != NULL)		nat_hostmapdel(hm);	KFREE(nat);	return NULL;}void	nat_insert(nat)nat_t	*nat;{	nat_t **natp;	u_int hv;	MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL);	nat->nat_age = fr_defnatage;	nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0';	if (nat->nat_ifname[0] !='\0') {		nat->nat_ifp = GETUNIT(nat->nat_ifname, 4);	}	nat->nat_next = nat_instances;	nat_instances = nat;	hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,			 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, nat->nat_outport,			 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;	nat_stats.ns_added++;	nat_stats.ns_inuse++;}nat_t *nat_icmplookup(ip, fin, dir)ip_t *ip;fr_info_t *fin;int dir;{	icmphdr_t *icmp;	tcphdr_t *tcp = NULL;	ip_t *oip;	int flags = 0, type, minlen;	icmp = (icmphdr_t *)fin->fin_dp;	/*	 * Does it at least have the return (basic) IP header ?	 * Only a basic IP header (no options) should be with an ICMP error	 * header.	 */	if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN))		return NULL;	type = icmp->icmp_type;	/*	 * If it's not an error type, then return.	 */	if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&	    (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&	    (type != ICMP_PARAMPROB))		return NULL;	oip = (ip_t *)((char *)fin->fin_dp + 8);	minlen = (oip->ip_hl << 2);	if (minlen < sizeof(ip_t))		return NULL;	if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)		return NULL;	/*	 * Is the buffer big enough for all of it ?  It's the size of the IP	 * header claimed in the encapsulated part which is of concern.  It	 * may be too big to be in this buffer but not so big that it's	 * outside the ICMP packet, leading to TCP deref's causing problems.	 * This is possible because we don't know how big oip_hl is when we	 * do the pullup early in fr_check() and thus can't gaurantee it is	 * all here now.	 */#ifdef  _KERNEL	{	mb_t *m;# if SOLARIS	m = fin->fin_qfm;	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)		return NULL;# else	m = *(mb_t **)fin->fin_mp;	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >	    (char *)ip + m->m_len)		return NULL;# endif	}#endif	if (oip->ip_p == IPPROTO_TCP)		flags = IPN_TCP;	else if (oip->ip_p == IPPROTO_UDP)		flags = IPN_UDP;	if (flags & IPN_TCPUDP) {		minlen += 8;		/* + 64bits of data to get ports */		if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)			return NULL;		tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));		if (dir == NAT_INBOUND)			return nat_inlookup(fin->fin_ifp, flags,				(u_int)oip->ip_p, oip->ip_dst, oip->ip_src,				(tcp->th_sport << 16) | tcp->th_dport, 0);		else			return nat_outlookup(fin->fin_ifp, flags,				(u_int)oip->ip_p, oip->ip_dst, oip->ip_src,				(tcp->th_sport << 16) | tcp->th_dport, 0);	}	if (dir == NAT_INBOUND)		return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,			oip->ip_dst, oip->ip_src, 0, 0);	else		return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,			oip->ip_dst, oip->ip_src, 0, 0);}/* * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP * packet gets correctly recognised. */nat_t *nat_icmp(ip, fin, nflags, dir)ip_t *ip;fr_info_t *fin;u_int *nflags;int dir;{	u_32_t sum1, sum2, sumd, sumd2 = 0;	struct in_addr in;	icmphdr_t *icmp;	udphdr_t *udp;	nat_t *nat;	ip_t *oip;	int flags = 0;	if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK))		return NULL;	/*	 * nat_icmplookup() will return NULL for `defective' packets.	 */

⌨️ 快捷键说明

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