xref: /onnv-gate/usr/src/uts/common/inet/ipf/ip_htable.c (revision 12255:f9a1f4ae1259)
12393Syz155240 /*
22393Syz155240  * Copyright (C) 1993-2001, 2003 by Darren Reed.
32393Syz155240  *
42393Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
52393Syz155240  *
6*12255SJohn.Ojemann@Oracle.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
72393Syz155240  */
82393Syz155240 
92393Syz155240 #if defined(KERNEL) || defined(_KERNEL)
102393Syz155240 # undef KERNEL
112393Syz155240 # undef _KERNEL
122393Syz155240 # define        KERNEL	1
132393Syz155240 # define        _KERNEL	1
142393Syz155240 #endif
152393Syz155240 #include <sys/param.h>
162393Syz155240 #include <sys/types.h>
172393Syz155240 #include <sys/errno.h>
182393Syz155240 #include <sys/time.h>
192393Syz155240 #include <sys/file.h>
202393Syz155240 #if !defined(_KERNEL)
212393Syz155240 # include <stdlib.h>
222393Syz155240 # include <string.h>
232393Syz155240 # define _KERNEL
242393Syz155240 # ifdef __OpenBSD__
252393Syz155240 struct file;
262393Syz155240 # endif
272393Syz155240 # include <sys/uio.h>
282393Syz155240 # undef _KERNEL
292393Syz155240 #endif
302393Syz155240 #include <sys/socket.h>
312393Syz155240 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
322393Syz155240 # include <sys/malloc.h>
332393Syz155240 #endif
342393Syz155240 #if defined(__FreeBSD__)
352393Syz155240 #  include <sys/cdefs.h>
362393Syz155240 #  include <sys/proc.h>
372393Syz155240 #endif
382393Syz155240 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
392393Syz155240     !defined(linux)
402393Syz155240 # include <sys/mbuf.h>
412393Syz155240 #endif
422393Syz155240 #if defined(_KERNEL)
432393Syz155240 # include <sys/systm.h>
442393Syz155240 #else
452393Syz155240 # include <stdio.h>
462393Syz155240 #endif
472393Syz155240 #include <netinet/in.h>
482393Syz155240 #include <net/if.h>
492393Syz155240 
502393Syz155240 #include "netinet/ip_compat.h"
512393Syz155240 #include "netinet/ip_fil.h"
522393Syz155240 #include "netinet/ip_lookup.h"
532393Syz155240 #include "netinet/ip_htable.h"
543448Sdh155122 #include "netinet/ipf_stack.h"
552393Syz155240 /* END OF INCLUDES */
562393Syz155240 
572393Syz155240 #if !defined(lint)
582393Syz155240 static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $";
592393Syz155240 #endif
602393Syz155240 
612393Syz155240 #ifdef	IPFILTER_LOOKUP
622393Syz155240 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
632393Syz155240 #ifdef USE_INET6
642393Syz155240 static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *));
652393Syz155240 static uint32_t sum4(uint32_t *);
662393Syz155240 static void left_shift_ipv6 __P((char *));
672393Syz155240 #endif
682393Syz155240 
fr_htable_unload(ifs)693448Sdh155122 void fr_htable_unload(ifs)
703448Sdh155122 ipf_stack_t *ifs;
712393Syz155240 {
722393Syz155240 	iplookupflush_t fop;
732393Syz155240 
742393Syz155240 	fop.iplf_unit = IPL_LOGALL;
753448Sdh155122 	(void)fr_flushhtable(&fop, ifs);
762393Syz155240 }
772393Syz155240 
782393Syz155240 
fr_gethtablestat(op,ifs)793448Sdh155122 int fr_gethtablestat(op, ifs)
802393Syz155240 iplookupop_t *op;
813448Sdh155122 ipf_stack_t *ifs;
822393Syz155240 {
832393Syz155240 	iphtstat_t stats;
842393Syz155240 
852393Syz155240 	if (op->iplo_size != sizeof(stats))
862393Syz155240 		return EINVAL;
872393Syz155240 
883448Sdh155122 	stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit];
893448Sdh155122 	stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit];
903448Sdh155122 	stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit];
913448Sdh155122 	stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit];
922393Syz155240 
932393Syz155240 	return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
942393Syz155240 
952393Syz155240 }
962393Syz155240 
972393Syz155240 
982393Syz155240 /*
992393Syz155240  * Create a new hash table using the template passed.
1002393Syz155240  */
fr_newhtable(op,ifs)1013448Sdh155122 int fr_newhtable(op, ifs)
1022393Syz155240 iplookupop_t *op;
1033448Sdh155122 ipf_stack_t *ifs;
1042393Syz155240 {
1052393Syz155240 	iphtable_t *iph, *oiph;
1062393Syz155240 	char name[FR_GROUPLEN];
1072393Syz155240 	int err, i, unit;
1082393Syz155240 
1092393Syz155240 	KMALLOC(iph, iphtable_t *);
1102393Syz155240 	if (iph == NULL) {
1113448Sdh155122 		ifs->ifs_ipht_nomem[op->iplo_unit]++;
1122393Syz155240 		return ENOMEM;
1132393Syz155240 	}
1142393Syz155240 
1152393Syz155240 	err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
1162393Syz155240 	if (err != 0) {
1172393Syz155240 		KFREE(iph);
1182393Syz155240 		return EFAULT;
1192393Syz155240 	}
1202393Syz155240 
1212393Syz155240 	unit = op->iplo_unit;
1222393Syz155240 	if (iph->iph_unit != unit) {
1232393Syz155240 		KFREE(iph);
1242393Syz155240 		return EINVAL;
1252393Syz155240 	}
1262393Syz155240 
1272393Syz155240 	if ((op->iplo_arg & IPHASH_ANON) == 0) {
1283448Sdh155122 		if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) {
1292393Syz155240 			KFREE(iph);
1302393Syz155240 			return EEXIST;
1312393Syz155240 		}
1322393Syz155240 	} else {
1332393Syz155240 		i = IPHASH_ANON;
1342393Syz155240 		do {
1352393Syz155240 			i++;
1362393Syz155240 #if defined(SNPRINTF) && defined(_KERNEL)
1372393Syz155240 			(void)SNPRINTF(name, sizeof(name), "%u", i);
1382393Syz155240 #else
1392393Syz155240 			(void)sprintf(name, "%u", i);
1402393Syz155240 #endif
1413448Sdh155122 			for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL;
1422393Syz155240 			     oiph = oiph->iph_next)
1432393Syz155240 				if (strncmp(oiph->iph_name, name,
1442393Syz155240 					    sizeof(oiph->iph_name)) == 0)
1452393Syz155240 					break;
1462393Syz155240 		} while (oiph != NULL);
1472393Syz155240 		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
1482393Syz155240 		err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
1492393Syz155240 		if (err != 0) {
1502393Syz155240 			KFREE(iph);
1512393Syz155240 			return EFAULT;
1522393Syz155240 		}
1532393Syz155240 		iph->iph_type |= IPHASH_ANON;
1542393Syz155240 	}
1552393Syz155240 
1562393Syz155240 	KMALLOCS(iph->iph_table, iphtent_t **,
1572393Syz155240 		 iph->iph_size * sizeof(*iph->iph_table));
1582393Syz155240 	if (iph->iph_table == NULL) {
1592393Syz155240 		KFREE(iph);
1603448Sdh155122 		ifs->ifs_ipht_nomem[unit]++;
1612393Syz155240 		return ENOMEM;
1622393Syz155240 	}
1632393Syz155240 
1642393Syz155240 	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
1652393Syz155240 	iph->iph_masks[0] = 0;
1662393Syz155240 	iph->iph_masks[1] = 0;
1672393Syz155240 	iph->iph_masks[2] = 0;
1682393Syz155240 	iph->iph_masks[3] = 0;
1693448Sdh155122 	iph->iph_list = NULL;
1702393Syz155240 
1713448Sdh155122 	iph->iph_ref = 1;
1723448Sdh155122 	iph->iph_next = ifs->ifs_ipf_htables[unit];
1733448Sdh155122 	iph->iph_pnext = &ifs->ifs_ipf_htables[unit];
1743448Sdh155122 	if (ifs->ifs_ipf_htables[unit] != NULL)
1753448Sdh155122 		ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next;
1763448Sdh155122 	ifs->ifs_ipf_htables[unit] = iph;
1772393Syz155240 
1783448Sdh155122 	ifs->ifs_ipf_nhtables[unit]++;
1792393Syz155240 
1802393Syz155240 	return 0;
1812393Syz155240 }
1822393Syz155240 
1832393Syz155240 
1842393Syz155240 /*
1852393Syz155240  */
fr_removehtable(op,ifs)1863448Sdh155122 int fr_removehtable(op, ifs)
1872393Syz155240 iplookupop_t *op;
1883448Sdh155122 ipf_stack_t *ifs;
1892393Syz155240 {
1902393Syz155240 	iphtable_t *iph;
1912393Syz155240 
1922393Syz155240 
1933448Sdh155122 	iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs);
1942393Syz155240 	if (iph == NULL)
1952393Syz155240 		return ESRCH;
1962393Syz155240 
1972393Syz155240 	if (iph->iph_unit != op->iplo_unit) {
1982393Syz155240 		return EINVAL;
1992393Syz155240 	}
2003448Sdh155122 
2013448Sdh155122 	if (iph->iph_ref != 1) {
2022393Syz155240 		return EBUSY;
2032393Syz155240 	}
2042393Syz155240 
2053448Sdh155122 	fr_delhtable(iph, ifs);
2062393Syz155240 
2072393Syz155240 	return 0;
2082393Syz155240 }
2092393Syz155240 
2102393Syz155240 
fr_delhtable(iph,ifs)2113448Sdh155122 void fr_delhtable(iph, ifs)
2122393Syz155240 iphtable_t *iph;
2133448Sdh155122 ipf_stack_t *ifs;
2142393Syz155240 {
2152393Syz155240 	iphtent_t *ipe;
2162393Syz155240 	int i;
2172393Syz155240 
2182393Syz155240 	for (i = 0; i < iph->iph_size; i++)
2192393Syz155240 		while ((ipe = iph->iph_table[i]) != NULL)
2203448Sdh155122 			if (fr_delhtent(iph, ipe, ifs) != 0)
2212393Syz155240 				return;
2222393Syz155240 
2232393Syz155240 	*iph->iph_pnext = iph->iph_next;
2242393Syz155240 	if (iph->iph_next != NULL)
2252393Syz155240 		iph->iph_next->iph_pnext = iph->iph_pnext;
2262393Syz155240 
2273448Sdh155122 	ifs->ifs_ipf_nhtables[iph->iph_unit]--;
2282393Syz155240 
2293448Sdh155122 	if (iph->iph_ref == 1) {
2302393Syz155240 		KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
2312393Syz155240 		KFREE(iph);
2322393Syz155240 	}
2332393Syz155240 }
2342393Syz155240 
2352393Syz155240 
fr_derefhtable(iph,ifs)2363448Sdh155122 void fr_derefhtable(iph, ifs)
2372393Syz155240 iphtable_t *iph;
2383448Sdh155122 ipf_stack_t *ifs;
2392393Syz155240 {
2402393Syz155240 	iph->iph_ref--;
2412393Syz155240 	if (iph->iph_ref == 0)
2423448Sdh155122 		fr_delhtable(iph, ifs);
2432393Syz155240 }
2442393Syz155240 
2452393Syz155240 
fr_derefhtent(ipe)2463448Sdh155122 void fr_derefhtent(ipe)
2473448Sdh155122 iphtent_t *ipe;
2483448Sdh155122 {
2493448Sdh155122 	ipe->ipe_ref--;
2503448Sdh155122 	if (ipe->ipe_ref == 0) {
2513448Sdh155122 		KFREE(ipe);
2523448Sdh155122 	}
2533448Sdh155122 }
2543448Sdh155122 
2553448Sdh155122 
fr_findhtable(unit,name,ifs)2563448Sdh155122 iphtable_t *fr_findhtable(unit, name, ifs)
2572393Syz155240 int unit;
2582393Syz155240 char *name;
2593448Sdh155122 ipf_stack_t *ifs;
2602393Syz155240 {
2612393Syz155240 	iphtable_t *iph;
2622393Syz155240 
2633448Sdh155122 	for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
2642393Syz155240 		if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
2652393Syz155240 			break;
2662393Syz155240 	return iph;
2672393Syz155240 }
2682393Syz155240 
2692393Syz155240 
fr_flushhtable(op,ifs)2703448Sdh155122 size_t fr_flushhtable(op, ifs)
2712393Syz155240 iplookupflush_t *op;
2723448Sdh155122 ipf_stack_t *ifs;
2732393Syz155240 {
2742393Syz155240 	iphtable_t *iph;
2752393Syz155240 	size_t freed;
2762393Syz155240 	int i;
2772393Syz155240 
2782393Syz155240 	freed = 0;
2792393Syz155240 
2802393Syz155240 	for (i = 0; i <= IPL_LOGMAX; i++) {
2812393Syz155240 		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
2823448Sdh155122 			while ((iph = ifs->ifs_ipf_htables[i]) != NULL) {
2833448Sdh155122 				fr_delhtable(iph, ifs);
2842393Syz155240 				freed++;
2852393Syz155240 			}
2862393Syz155240 		}
2872393Syz155240 	}
2882393Syz155240 
2892393Syz155240 	return freed;
2902393Syz155240 }
2912393Syz155240 
2922393Syz155240 
2932393Syz155240 /*
2942393Syz155240  * Add an entry to a hash table.
2952393Syz155240  */
fr_addhtent(iph,ipeo,ifs)2963448Sdh155122 int fr_addhtent(iph, ipeo, ifs)
2972393Syz155240 iphtable_t *iph;
2982393Syz155240 iphtent_t *ipeo;
2993448Sdh155122 ipf_stack_t *ifs;
3002393Syz155240 {
3012393Syz155240 	iphtent_t *ipe;
3022393Syz155240 	u_int hv;
3032393Syz155240 	int bits;
3042393Syz155240 
3052393Syz155240 	KMALLOC(ipe, iphtent_t *);
3062393Syz155240 	if (ipe == NULL)
3072393Syz155240 		return -1;
3082393Syz155240 
3092393Syz155240 	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
3102393Syz155240 #ifdef USE_INET6
3112393Syz155240 	if (ipe->ipe_family == AF_INET6) {
3122393Syz155240 		bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8);
3132393Syz155240 		hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8),
3142393Syz155240 				 sum4((uint32_t *)ipe->ipe_mask.in6_addr8),
3152393Syz155240 				 iph->iph_size);
3162393Syz155240 	} else
3172393Syz155240 #endif
3182393Syz155240 	if (ipe->ipe_family == AF_INET)
3192393Syz155240 	{
3202393Syz155240 		ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
3212393Syz155240 		ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
3222393Syz155240 		bits = count4bits(ipe->ipe_mask.in4_addr);
3232393Syz155240 		ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
3242393Syz155240 
3252393Syz155240 		hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
3262393Syz155240 				 iph->iph_size);
3272393Syz155240 	} else
3282393Syz155240 		return -1;
3292393Syz155240 
3303448Sdh155122 	ipe->ipe_ref = 1;
3312393Syz155240 	ipe->ipe_next = iph->iph_table[hv];
3322393Syz155240 	ipe->ipe_pnext = iph->iph_table + hv;
3332393Syz155240 
3342393Syz155240 	if (iph->iph_table[hv] != NULL)
3352393Syz155240 		iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
3362393Syz155240 	iph->iph_table[hv] = ipe;
3373448Sdh155122 
3383448Sdh155122 	ipe->ipe_snext = iph->iph_list;
3393448Sdh155122 	ipe->ipe_psnext = &iph->iph_list;
3403448Sdh155122 	if (ipe->ipe_next != NULL)
3413448Sdh155122 		ipe->ipe_next->ipe_psnext = &ipe->ipe_snext;
3423448Sdh155122 	iph->iph_list = ipe;
3433448Sdh155122 
3442393Syz155240 #ifdef USE_INET6
3452393Syz155240 	if (ipe->ipe_family == AF_INET6) {
3462393Syz155240 		if ((bits >= 0) && (bits != 128))
3472393Syz155240 			if (bits >= 96)
3482393Syz155240 				iph->iph_masks[0] |= 1 << (bits - 96);
3492393Syz155240 			else if (bits >= 64)
3502393Syz155240 				iph->iph_masks[1] |= 1 << (bits - 64);
3512393Syz155240 			else if (bits >= 32)
3522393Syz155240 				iph->iph_masks[2] |= 1 << (bits - 32);
3532393Syz155240 			else
3542393Syz155240 				iph->iph_masks[3] |= 1 << bits;
3552393Syz155240 
3562393Syz155240 	} else
3572393Syz155240 #endif
3582393Syz155240 	{
3592393Syz155240 		if ((bits >= 0) && (bits != 32))
3602393Syz155240 			iph->iph_masks[3] |= 1 << bits;
3612393Syz155240 	}
3622393Syz155240 
3632393Syz155240 	switch (iph->iph_type & ~IPHASH_ANON)
3642393Syz155240 	{
3652393Syz155240 	case IPHASH_GROUPMAP :
3662393Syz155240 		ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
3672393Syz155240 					   iph->iph_flags, IPL_LOGIPF,
3683448Sdh155122 					   ifs->ifs_fr_active, ifs);
3692393Syz155240 		break;
3702393Syz155240 
3712393Syz155240 	default :
3722393Syz155240 		ipe->ipe_ptr = NULL;
3732393Syz155240 		ipe->ipe_value = 0;
3742393Syz155240 		break;
3752393Syz155240 	}
3762393Syz155240 
3773448Sdh155122 	ifs->ifs_ipf_nhtnodes[iph->iph_unit]++;
3782393Syz155240 
3792393Syz155240 	return 0;
3802393Syz155240 }
3812393Syz155240 
3822393Syz155240 
3832393Syz155240 /*
3842393Syz155240  * Delete an entry from a hash table.
3852393Syz155240  */
fr_delhtent(iph,ipe,ifs)3863448Sdh155122 int fr_delhtent(iph, ipe, ifs)
3872393Syz155240 iphtable_t *iph;
3882393Syz155240 iphtent_t *ipe;
3893448Sdh155122 ipf_stack_t *ifs;
3902393Syz155240 {
3913448Sdh155122 	if (ipe->ipe_ref != 1)
3922393Syz155240 		return EBUSY;
3932393Syz155240 
3942393Syz155240 
3952393Syz155240 	*ipe->ipe_pnext = ipe->ipe_next;
3962393Syz155240 	if (ipe->ipe_next != NULL)
3972393Syz155240 		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
3982393Syz155240 
3992393Syz155240 	switch (iph->iph_type & ~IPHASH_ANON)
4002393Syz155240 	{
4012393Syz155240 	case IPHASH_GROUPMAP :
4022393Syz155240 		if (ipe->ipe_group != NULL)
4033448Sdh155122 			fr_delgroup(ipe->ipe_group, IPL_LOGIPF,
4043448Sdh155122 				    ifs->ifs_fr_active, ifs);
4052393Syz155240 		break;
4062393Syz155240 
4072393Syz155240 	default :
4082393Syz155240 		ipe->ipe_ptr = NULL;
4092393Syz155240 		ipe->ipe_value = 0;
4102393Syz155240 		break;
4112393Syz155240 	}
4122393Syz155240 
4132393Syz155240 	KFREE(ipe);
4142393Syz155240 
4153448Sdh155122 	ifs->ifs_ipf_nhtnodes[iph->iph_unit]--;
4163448Sdh155122 
4172393Syz155240 	return 0;
4182393Syz155240 }
4192393Syz155240 
4202393Syz155240 
fr_iphmfindgroup(tptr,version,aptr,ifs)4213448Sdh155122 void *fr_iphmfindgroup(tptr, version, aptr, ifs)
4222393Syz155240 void *tptr;
4232393Syz155240 int version;
4242393Syz155240 void *aptr;
4253448Sdh155122 ipf_stack_t *ifs;
4262393Syz155240 {
4272393Syz155240 	i6addr_t *addr;
4282393Syz155240 	iphtable_t *iph;
4292393Syz155240 	iphtent_t *ipe;
4302393Syz155240 	void *rval;
4312393Syz155240 
4322393Syz155240 	if ((version != 4)
4332393Syz155240 #ifdef USE_INET6
4342393Syz155240 	    && (version != 6)
4352393Syz155240 #endif
4362393Syz155240 	    )
4372393Syz155240 		return NULL;
4382393Syz155240 
4393448Sdh155122 	READ_ENTER(&ifs->ifs_ip_poolrw);
4402393Syz155240 	iph = tptr;
4412393Syz155240 	addr = aptr;
4422393Syz155240 
4432393Syz155240 #ifdef USE_INET6
4442393Syz155240 	if (version == 6)
4452393Syz155240 		ipe = fr_iphmfind6(iph, &addr->in6);
4462393Syz155240 	else
4472393Syz155240 #endif
4482393Syz155240 	if (version == 4)
4492393Syz155240 		ipe = fr_iphmfind(iph, &addr->in4);
4502393Syz155240 	else
4512393Syz155240 		ipe = NULL;
4522393Syz155240 	if (ipe != NULL)
4532393Syz155240 		rval = ipe->ipe_ptr;
4542393Syz155240 	else
4552393Syz155240 		rval = NULL;
4563448Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
4572393Syz155240 	return rval;
4582393Syz155240 }
4592393Syz155240 
4602393Syz155240 
4612393Syz155240 /* ------------------------------------------------------------------------ */
4622393Syz155240 /* Function:    fr_iphmfindip                                               */
4632393Syz155240 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
4642393Syz155240 /* Parameters:  tptr(I)    - pointer to the pool to search                  */
4652393Syz155240 /*              version(I) - IP protocol version (4 or 6)                   */
4662393Syz155240 /*              aptr(I)    - pointer to address information                 */
467*12255SJohn.Ojemann@Oracle.COM /*		fin	   - pointer to packet information		    */
468*12255SJohn.Ojemann@Oracle.COM /*		ifs	   - ipf stack instance				    */
4692393Syz155240 /*                                                                          */
4702393Syz155240 /* Search the hash table for a given address and return a search result.    */
4712393Syz155240 /* ------------------------------------------------------------------------ */
fr_iphmfindip(tptr,version,aptr,fin,ifs)472*12255SJohn.Ojemann@Oracle.COM int fr_iphmfindip(tptr, version, aptr, fin, ifs)
4732393Syz155240 void *tptr, *aptr;
4742393Syz155240 int version;
475*12255SJohn.Ojemann@Oracle.COM fr_info_t *fin;
4763448Sdh155122 ipf_stack_t *ifs;
4772393Syz155240 {
4782393Syz155240 	i6addr_t *addr;
4792393Syz155240 	iphtable_t *iph;
4802393Syz155240 	iphtent_t *ipe;
4812393Syz155240 	int rval;
4822393Syz155240 
4832393Syz155240 	if ((version != 4)
4842393Syz155240 #ifdef USE_INET6
4852393Syz155240 	    && (version != 6)
4862393Syz155240 #endif
4872393Syz155240 	    )
4882393Syz155240 		return -1;
4892393Syz155240 
4902393Syz155240 	if (tptr == NULL || aptr == NULL)
4912393Syz155240 		return -1;
4922393Syz155240 
4932393Syz155240 	iph = tptr;
4942393Syz155240 	addr = aptr;
4952393Syz155240 
4963448Sdh155122 	READ_ENTER(&ifs->ifs_ip_poolrw);
4972393Syz155240 #ifdef USE_INET6
4982393Syz155240 	if (version == 6)
4992393Syz155240 		ipe = fr_iphmfind6(iph, &addr->in6);
5002393Syz155240 	else
5012393Syz155240 #endif
5022393Syz155240 	if (version == 4)
5032393Syz155240 		ipe = fr_iphmfind(iph, &addr->in4);
5042393Syz155240 	else
5052393Syz155240 		ipe = NULL;
506*12255SJohn.Ojemann@Oracle.COM 	if (ipe != NULL) {
507*12255SJohn.Ojemann@Oracle.COM 		ipe->ipe_hits++;
508*12255SJohn.Ojemann@Oracle.COM 		ipe->ipe_bytes += fin->fin_plen;
5092393Syz155240 		rval = 0;
510*12255SJohn.Ojemann@Oracle.COM 	} else {
5112393Syz155240 		rval = 1;
512*12255SJohn.Ojemann@Oracle.COM 	}
5133448Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
5142393Syz155240 	return rval;
5152393Syz155240 }
5162393Syz155240 
5172393Syz155240 
5182393Syz155240 /* Locks:  ip_poolrw */
fr_iphmfind(iph,addr)5192393Syz155240 static iphtent_t *fr_iphmfind(iph, addr)
5202393Syz155240 iphtable_t *iph;
5212393Syz155240 struct in_addr *addr;
5222393Syz155240 {
5232393Syz155240 	u_32_t hmsk, msk, ips;
5242393Syz155240 	iphtent_t *ipe;
5252393Syz155240 	u_int hv;
5262393Syz155240 
5272393Syz155240 	hmsk = iph->iph_masks[3];
5282393Syz155240 	msk = 0xffffffff;
5292393Syz155240 maskloop:
5302393Syz155240 	ips = ntohl(addr->s_addr) & msk;
5312393Syz155240 	hv = IPE_HASH_FN(ips, msk, iph->iph_size);
5322393Syz155240 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
5332393Syz155240 		if (ipe->ipe_mask.in4_addr != msk ||
5342393Syz155240 		    ipe->ipe_addr.in4_addr != ips) {
5352393Syz155240 			continue;
5362393Syz155240 		}
5372393Syz155240 		break;
5382393Syz155240 	}
5392393Syz155240 
5402393Syz155240 	if ((ipe == NULL) && (hmsk != 0)) {
5412393Syz155240 		while (hmsk != 0) {
5422393Syz155240 			msk <<= 1;
5432393Syz155240 			if (hmsk & 0x80000000)
5442393Syz155240 				break;
5452393Syz155240 			hmsk <<= 1;
5462393Syz155240 		}
5472393Syz155240 		if (hmsk != 0) {
5482393Syz155240 			hmsk <<= 1;
5492393Syz155240 			goto maskloop;
5502393Syz155240 		}
5512393Syz155240 	}
5522393Syz155240 	return ipe;
5532393Syz155240 }
5542393Syz155240 
5552393Syz155240 
5562393Syz155240 #ifdef USE_INET6
5572393Syz155240 /* Locks:  ip_poolrw */
fr_iphmfind6(iph,addr)5582393Syz155240 static iphtent_t *fr_iphmfind6(iph, addr)
5592393Syz155240 iphtable_t *iph;
5602393Syz155240 struct in6_addr *addr;
5612393Syz155240 {
5622393Syz155240 	u_32_t hmsk[4], msk[4], ips[4], *and;
5632393Syz155240 	iphtent_t *ipe;
5642393Syz155240 	u_int hv;
5652393Syz155240 
5662393Syz155240 	hmsk[0] = iph->iph_masks[0];
5672393Syz155240 	hmsk[1] = iph->iph_masks[1];
5682393Syz155240 	hmsk[2] = iph->iph_masks[2];
5692393Syz155240 	hmsk[3] = iph->iph_masks[3];
5702393Syz155240 
5712393Syz155240 	msk[0] = 0xffffffff;
5722393Syz155240 	msk[1] = 0xffffffff;
5732393Syz155240 	msk[2] = 0xffffffff;
5742393Syz155240 	msk[3] = 0xffffffff;
5752393Syz155240 maskloop:
5762393Syz155240 	and = (u_32_t *)addr->s6_addr;
5772393Syz155240 	ips[0] = *and & msk[0];
5782393Syz155240 	ips[1] = *(and + 1) & msk[1];
5792393Syz155240 	ips[2] = *(and + 2) & msk[2];
5802393Syz155240 	ips[3] = *(and + 3) & msk[3];
5812393Syz155240 
5822393Syz155240 	hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk),
5832393Syz155240 			      iph->iph_size);
5842393Syz155240 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
5852393Syz155240 		if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) ||
5862393Syz155240 		    bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16))
5872393Syz155240 			continue;
5882393Syz155240 		break;
5892393Syz155240 	}
5902393Syz155240 
5912393Syz155240 	if ((ipe == NULL) && ((hmsk[0] != 0) ||
5922393Syz155240 			      (hmsk[1] != 0) ||
5932393Syz155240 			      (hmsk[2] != 0) ||
5942393Syz155240 			      (hmsk[3] != 0) )) {
5952393Syz155240 		while ((hmsk[0] != 0) && (hmsk[1] != 0) &&
5962393Syz155240 		       (hmsk[2] != 0) && (hmsk[3] != 0)) {
5972393Syz155240 			left_shift_ipv6((char *)msk);
5982393Syz155240 			if (hmsk[0] & 0x80000000)
5992393Syz155240 				break;
6002393Syz155240 			left_shift_ipv6((char *)hmsk);
6012393Syz155240 		}
6022393Syz155240 		if ((hmsk[0] != 0) && (hmsk[1] != 0) &&
6032393Syz155240 		    (hmsk[2] != 0) && (hmsk[3] != 0)) {
6042393Syz155240 			left_shift_ipv6((char *)hmsk);
6052393Syz155240 			goto maskloop;
6062393Syz155240 		}
6072393Syz155240 	}
6082393Syz155240 	return ipe;
6092393Syz155240 }
6102393Syz155240 
6112393Syz155240 
6122393Syz155240 /*
6132393Syz155240  * sum4: ipv6 add -> 4 bytes values
6142393Syz155240  */
sum4(add)6152393Syz155240 static uint32_t sum4(add)
6162393Syz155240 uint32_t *add;
6172393Syz155240 {
6182393Syz155240 	return (*add + *(add + 1) + *(add + 2) + *(add + 3));
6192393Syz155240 }
6202393Syz155240 
6212393Syz155240 /*
6222393Syz155240  * left shift on 128 bits
6232393Syz155240  */
left_shift_ipv6(data)6242393Syz155240 static void left_shift_ipv6(data)
6252393Syz155240 char *data;
6262393Syz155240 {
6272393Syz155240 	u_32_t *sd;
6282393Syz155240 
6292393Syz155240 	sd = (u_32_t *)data;
6302393Syz155240 	sd[0] <<= 1;
6312393Syz155240 	if (sd[1] >= 0x80000000)
6322393Syz155240 		sd[0] += 1;
6332393Syz155240 
6342393Syz155240 	sd[1] <<= 1;
6352393Syz155240 	if (sd[2] >= 0x80000000)
6362393Syz155240 		sd[1] += 1;
6372393Syz155240 
6382393Syz155240 	sd[2] <<= 1;
6392393Syz155240 	if (sd[3] >= 0x80000000)
6402393Syz155240 		sd[2] += 1;
6412393Syz155240 
6422393Syz155240 	sd[3] <<= 1;
6432393Syz155240 }
6442393Syz155240 #endif
6453448Sdh155122 
fr_htable_getnext(token,ilp,ifs)6463448Sdh155122 int fr_htable_getnext(token, ilp, ifs)
6473448Sdh155122 ipftoken_t *token;
6483448Sdh155122 ipflookupiter_t *ilp;
6493448Sdh155122 ipf_stack_t *ifs;
6503448Sdh155122 {
6513448Sdh155122 	iphtent_t *node, zn, *nextnode;
6523448Sdh155122 	iphtable_t *iph, zp, *nextiph;
6533448Sdh155122 	int err;
6543448Sdh155122 
6553448Sdh155122 	err = 0;
6563448Sdh155122 	iph = NULL;
6573448Sdh155122 	node = NULL;
6583448Sdh155122 	nextiph = NULL;
6593448Sdh155122 	nextnode = NULL;
6603448Sdh155122 
6613448Sdh155122 	READ_ENTER(&ifs->ifs_ip_poolrw);
6623448Sdh155122 
6636518Sjojemann 	/*
6646518Sjojemann 	 * Get "previous" entry from the token and find the next entry.
6656518Sjojemann 	 *
6666518Sjojemann 	 * If we found an entry, add a reference to it and update the token.
6676518Sjojemann 	 * Otherwise, zero out data to be returned and NULL out token.
6686518Sjojemann 	 */
6693448Sdh155122 	switch (ilp->ili_otype)
6703448Sdh155122 	{
6713448Sdh155122 	case IPFLOOKUPITER_LIST :
6723448Sdh155122 		iph = token->ipt_data;
6733448Sdh155122 		if (iph == NULL) {
6743448Sdh155122 			nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit];
6753448Sdh155122 		} else {
6763448Sdh155122 			nextiph = iph->iph_next;
6773448Sdh155122 		}
6783448Sdh155122 		if (nextiph != NULL) {
6796518Sjojemann 			ATOMIC_INC(nextiph->iph_ref);
6806518Sjojemann 			token->ipt_data = nextiph;
6813448Sdh155122 		} else {
6823448Sdh155122 			bzero((char *)&zp, sizeof(zp));
6833448Sdh155122 			nextiph = &zp;
6846518Sjojemann 			token->ipt_data = NULL;
6853448Sdh155122 		}
6863448Sdh155122 		break;
6873448Sdh155122 
6883448Sdh155122 	case IPFLOOKUPITER_NODE :
6893448Sdh155122 		node = token->ipt_data;
6903448Sdh155122 		if (node == NULL) {
6913448Sdh155122 			iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs);
6923448Sdh155122 			if (iph == NULL)
6933448Sdh155122 				err = ESRCH;
6943448Sdh155122 			else {
6953448Sdh155122 				nextnode = iph->iph_list;
6963448Sdh155122 			}
6973448Sdh155122 		} else {
6983448Sdh155122 			nextnode = node->ipe_snext;
6993448Sdh155122 		}
7003448Sdh155122 		if (nextnode != NULL) {
7016518Sjojemann 			ATOMIC_INC(nextnode->ipe_ref);
7026518Sjojemann 			token->ipt_data = nextnode;
7033448Sdh155122 		} else {
7043448Sdh155122 			bzero((char *)&zn, sizeof(zn));
7053448Sdh155122 			nextnode = &zn;
7066518Sjojemann 			token->ipt_data = NULL;
7073448Sdh155122 		}
7083448Sdh155122 		break;
7096518Sjojemann 
7103448Sdh155122 	default :
7113448Sdh155122 		err = EINVAL;
7123448Sdh155122 		break;
7133448Sdh155122 	}
7143448Sdh155122 
7156518Sjojemann 	/*
7166518Sjojemann 	 * Now that we have ref, it's save to give up lock.
7176518Sjojemann 	 */
7183448Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
7193448Sdh155122 	if (err != 0)
7203448Sdh155122 		return err;
7213448Sdh155122 
7226518Sjojemann 	/*
7236518Sjojemann 	 * Copy out data and clean up references and token as needed.
7246518Sjojemann 	 */
7253448Sdh155122 	switch (ilp->ili_otype)
7263448Sdh155122 	{
7273448Sdh155122 	case IPFLOOKUPITER_LIST :
7283448Sdh155122 		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
7293448Sdh155122 		if (err != 0)
7303448Sdh155122 			err = EFAULT;
7316518Sjojemann 		if (token->ipt_data == NULL) {
7326518Sjojemann 			ipf_freetoken(token, ifs);
7336518Sjojemann 		} else {
7346518Sjojemann 			if (iph != NULL) {
7356518Sjojemann 				WRITE_ENTER(&ifs->ifs_ip_poolrw);
7366518Sjojemann 				fr_derefhtable(iph, ifs);
7376518Sjojemann 				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
7386518Sjojemann 			}
7396518Sjojemann 			if (nextiph->iph_next == NULL)
7406518Sjojemann 				ipf_freetoken(token, ifs);
7416518Sjojemann 		}
7423448Sdh155122 		break;
7433448Sdh155122 
7443448Sdh155122 	case IPFLOOKUPITER_NODE :
7453448Sdh155122 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
7463448Sdh155122 		if (err != 0)
7473448Sdh155122 			err = EFAULT;
7486518Sjojemann 		if (token->ipt_data == NULL) {
7496518Sjojemann 			ipf_freetoken(token, ifs);
7506518Sjojemann 		} else {
7516518Sjojemann 			if (node != NULL) {
7526518Sjojemann 				WRITE_ENTER(&ifs->ifs_ip_poolrw);
7536518Sjojemann 				fr_derefhtent(node);
7546518Sjojemann 				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
7556518Sjojemann 			}
7566518Sjojemann 			if (nextnode->ipe_snext == NULL)
7576518Sjojemann 				ipf_freetoken(token, ifs);
7586518Sjojemann 		}
7593448Sdh155122 		break;
7603448Sdh155122 	}
7613448Sdh155122 
7623448Sdh155122 	return err;
7633448Sdh155122 }
7643448Sdh155122 
7653448Sdh155122 
fr_htable_iterderef(otype,unit,data,ifs)7663448Sdh155122 void fr_htable_iterderef(otype, unit, data, ifs)
7673448Sdh155122 u_int otype;
7683448Sdh155122 int unit;
7693448Sdh155122 void *data;
7703448Sdh155122 ipf_stack_t *ifs;
7713448Sdh155122 {
7723448Sdh155122 
7733448Sdh155122 	if (data == NULL)
7743448Sdh155122 		return;
7753448Sdh155122 
7763448Sdh155122 	if (unit < 0 || unit > IPL_LOGMAX)
7773448Sdh155122 		return;
7783448Sdh155122 
7793448Sdh155122 	switch (otype)
7803448Sdh155122 	{
7813448Sdh155122 	case IPFLOOKUPITER_LIST :
7823448Sdh155122 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
7833448Sdh155122 		fr_derefhtable((iphtable_t *)data, ifs);
7843448Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
7853448Sdh155122 		break;
7863448Sdh155122 
7873448Sdh155122 	case IPFLOOKUPITER_NODE :
7883448Sdh155122 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
7893448Sdh155122 		fr_derefhtent((iphtent_t *)data);
7903448Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
7913448Sdh155122 		break;
7923448Sdh155122 	default :
7933448Sdh155122 		break;
7943448Sdh155122 	}
7953448Sdh155122 }
7962393Syz155240 #endif /* IPFILTER_LOOKUP */
797