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