17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (C) 1993-2001, 2003 by Darren Reed. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 57c478bd9Sstevel@tonic-gate * 6*f4b3ec61Sdh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 77c478bd9Sstevel@tonic-gate * Use is subject to license terms. 87c478bd9Sstevel@tonic-gate */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 137c478bd9Sstevel@tonic-gate # undef KERNEL 147c478bd9Sstevel@tonic-gate # undef _KERNEL 157c478bd9Sstevel@tonic-gate # define KERNEL 1 167c478bd9Sstevel@tonic-gate # define _KERNEL 1 177c478bd9Sstevel@tonic-gate #endif 187c478bd9Sstevel@tonic-gate #include <sys/param.h> 197c478bd9Sstevel@tonic-gate #include <sys/types.h> 207c478bd9Sstevel@tonic-gate #include <sys/errno.h> 217c478bd9Sstevel@tonic-gate #include <sys/time.h> 227c478bd9Sstevel@tonic-gate #include <sys/file.h> 237c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 247c478bd9Sstevel@tonic-gate # include <stdlib.h> 257c478bd9Sstevel@tonic-gate # include <string.h> 267c478bd9Sstevel@tonic-gate # define _KERNEL 277c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 287c478bd9Sstevel@tonic-gate struct file; 297c478bd9Sstevel@tonic-gate # endif 307c478bd9Sstevel@tonic-gate # include <sys/uio.h> 317c478bd9Sstevel@tonic-gate # undef _KERNEL 327c478bd9Sstevel@tonic-gate #endif 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 357c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 367c478bd9Sstevel@tonic-gate #endif 377c478bd9Sstevel@tonic-gate #if defined(__FreeBSD__) 387c478bd9Sstevel@tonic-gate # include <sys/cdefs.h> 397c478bd9Sstevel@tonic-gate # include <sys/proc.h> 407c478bd9Sstevel@tonic-gate #endif 41ab25eeb5Syz #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ 42ab25eeb5Syz !defined(linux) 437c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 447c478bd9Sstevel@tonic-gate #endif 457c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 467c478bd9Sstevel@tonic-gate # include <sys/systm.h> 477c478bd9Sstevel@tonic-gate #else 487c478bd9Sstevel@tonic-gate # include <stdio.h> 497c478bd9Sstevel@tonic-gate #endif 507c478bd9Sstevel@tonic-gate #include <netinet/in.h> 517c478bd9Sstevel@tonic-gate #include <net/if.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h" 547c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 557c478bd9Sstevel@tonic-gate #include "netinet/ip_lookup.h" 567c478bd9Sstevel@tonic-gate #include "netinet/ip_htable.h" 57*f4b3ec61Sdh #include "netinet/ipf_stack.h" 58ab25eeb5Syz /* END OF INCLUDES */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #if !defined(lint) 61ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $"; 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 657c478bd9Sstevel@tonic-gate static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); 667663b816Sml #ifdef USE_INET6 677663b816Sml static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *)); 687663b816Sml static uint32_t sum4(uint32_t *); 697663b816Sml static void left_shift_ipv6 __P((char *)); 707663b816Sml #endif 717c478bd9Sstevel@tonic-gate 72*f4b3ec61Sdh void fr_htable_unload(ifs) 73*f4b3ec61Sdh ipf_stack_t *ifs; 747c478bd9Sstevel@tonic-gate { 757c478bd9Sstevel@tonic-gate iplookupflush_t fop; 76ab25eeb5Syz 77ab25eeb5Syz fop.iplf_unit = IPL_LOGALL; 78*f4b3ec61Sdh (void)fr_flushhtable(&fop, ifs); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 81ab25eeb5Syz 82*f4b3ec61Sdh int fr_gethtablestat(op, ifs) 837663b816Sml iplookupop_t *op; 84*f4b3ec61Sdh ipf_stack_t *ifs; 857663b816Sml { 867663b816Sml iphtstat_t stats; 877663b816Sml 887663b816Sml if (op->iplo_size != sizeof(stats)) 897663b816Sml return EINVAL; 907663b816Sml 91*f4b3ec61Sdh stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit]; 92*f4b3ec61Sdh stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit]; 93*f4b3ec61Sdh stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit]; 94*f4b3ec61Sdh stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit]; 957663b816Sml 967663b816Sml return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 977663b816Sml 987663b816Sml } 997663b816Sml 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Create a new hash table using the template passed. 1037c478bd9Sstevel@tonic-gate */ 104*f4b3ec61Sdh int fr_newhtable(op, ifs) 1057c478bd9Sstevel@tonic-gate iplookupop_t *op; 106*f4b3ec61Sdh ipf_stack_t *ifs; 1077c478bd9Sstevel@tonic-gate { 1087c478bd9Sstevel@tonic-gate iphtable_t *iph, *oiph; 1097c478bd9Sstevel@tonic-gate char name[FR_GROUPLEN]; 1107c478bd9Sstevel@tonic-gate int err, i, unit; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate KMALLOC(iph, iphtable_t *); 113ab25eeb5Syz if (iph == NULL) { 114*f4b3ec61Sdh ifs->ifs_ipht_nomem[op->iplo_unit]++; 115ab25eeb5Syz return ENOMEM; 116ab25eeb5Syz } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); 1197c478bd9Sstevel@tonic-gate if (err != 0) { 1207c478bd9Sstevel@tonic-gate KFREE(iph); 1217c478bd9Sstevel@tonic-gate return EFAULT; 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate unit = op->iplo_unit; 1257c478bd9Sstevel@tonic-gate if (iph->iph_unit != unit) { 1267c478bd9Sstevel@tonic-gate KFREE(iph); 1277c478bd9Sstevel@tonic-gate return EINVAL; 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if ((op->iplo_arg & IPHASH_ANON) == 0) { 131*f4b3ec61Sdh if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) { 1327c478bd9Sstevel@tonic-gate KFREE(iph); 1337c478bd9Sstevel@tonic-gate return EEXIST; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate } else { 1367c478bd9Sstevel@tonic-gate i = IPHASH_ANON; 1377c478bd9Sstevel@tonic-gate do { 1387c478bd9Sstevel@tonic-gate i++; 139ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL) 140ab25eeb5Syz (void)SNPRINTF(name, sizeof(name), "%u", i); 141ab25eeb5Syz #else 1427c478bd9Sstevel@tonic-gate (void)sprintf(name, "%u", i); 143ab25eeb5Syz #endif 144*f4b3ec61Sdh for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL; 1457c478bd9Sstevel@tonic-gate oiph = oiph->iph_next) 1467c478bd9Sstevel@tonic-gate if (strncmp(oiph->iph_name, name, 1477c478bd9Sstevel@tonic-gate sizeof(oiph->iph_name)) == 0) 1487c478bd9Sstevel@tonic-gate break; 1497c478bd9Sstevel@tonic-gate } while (oiph != NULL); 1507c478bd9Sstevel@tonic-gate (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 1517c478bd9Sstevel@tonic-gate err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); 1527c478bd9Sstevel@tonic-gate if (err != 0) { 1537c478bd9Sstevel@tonic-gate KFREE(iph); 1547c478bd9Sstevel@tonic-gate return EFAULT; 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate iph->iph_type |= IPHASH_ANON; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate KMALLOCS(iph->iph_table, iphtent_t **, 1607c478bd9Sstevel@tonic-gate iph->iph_size * sizeof(*iph->iph_table)); 1617c478bd9Sstevel@tonic-gate if (iph->iph_table == NULL) { 1627c478bd9Sstevel@tonic-gate KFREE(iph); 163*f4b3ec61Sdh ifs->ifs_ipht_nomem[unit]++; 1647c478bd9Sstevel@tonic-gate return ENOMEM; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 1687663b816Sml iph->iph_masks[0] = 0; 1697663b816Sml iph->iph_masks[1] = 0; 1707663b816Sml iph->iph_masks[2] = 0; 1717663b816Sml iph->iph_masks[3] = 0; 172*f4b3ec61Sdh iph->iph_list = NULL; 1737c478bd9Sstevel@tonic-gate 174*f4b3ec61Sdh iph->iph_ref = 1; 175*f4b3ec61Sdh iph->iph_next = ifs->ifs_ipf_htables[unit]; 176*f4b3ec61Sdh iph->iph_pnext = &ifs->ifs_ipf_htables[unit]; 177*f4b3ec61Sdh if (ifs->ifs_ipf_htables[unit] != NULL) 178*f4b3ec61Sdh ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next; 179*f4b3ec61Sdh ifs->ifs_ipf_htables[unit] = iph; 1807663b816Sml 181*f4b3ec61Sdh ifs->ifs_ipf_nhtables[unit]++; 1827663b816Sml 1837c478bd9Sstevel@tonic-gate return 0; 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate */ 189*f4b3ec61Sdh int fr_removehtable(op, ifs) 1907c478bd9Sstevel@tonic-gate iplookupop_t *op; 191*f4b3ec61Sdh ipf_stack_t *ifs; 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate iphtable_t *iph; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate 196*f4b3ec61Sdh iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs); 1977c478bd9Sstevel@tonic-gate if (iph == NULL) 1987c478bd9Sstevel@tonic-gate return ESRCH; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate if (iph->iph_unit != op->iplo_unit) { 2017c478bd9Sstevel@tonic-gate return EINVAL; 2027c478bd9Sstevel@tonic-gate } 203*f4b3ec61Sdh 204*f4b3ec61Sdh if (iph->iph_ref != 1) { 2057c478bd9Sstevel@tonic-gate return EBUSY; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 208*f4b3ec61Sdh fr_delhtable(iph, ifs); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate return 0; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate 214*f4b3ec61Sdh void fr_delhtable(iph, ifs) 2157c478bd9Sstevel@tonic-gate iphtable_t *iph; 216*f4b3ec61Sdh ipf_stack_t *ifs; 2177c478bd9Sstevel@tonic-gate { 218ab25eeb5Syz iphtent_t *ipe; 219ab25eeb5Syz int i; 220ab25eeb5Syz 221ab25eeb5Syz for (i = 0; i < iph->iph_size; i++) 222ab25eeb5Syz while ((ipe = iph->iph_table[i]) != NULL) 223*f4b3ec61Sdh if (fr_delhtent(iph, ipe, ifs) != 0) 224ab25eeb5Syz return; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate *iph->iph_pnext = iph->iph_next; 2277c478bd9Sstevel@tonic-gate if (iph->iph_next != NULL) 2287c478bd9Sstevel@tonic-gate iph->iph_next->iph_pnext = iph->iph_pnext; 2297c478bd9Sstevel@tonic-gate 230*f4b3ec61Sdh ifs->ifs_ipf_nhtables[iph->iph_unit]--; 231ab25eeb5Syz 232*f4b3ec61Sdh if (iph->iph_ref == 1) { 233ab25eeb5Syz KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 234ab25eeb5Syz KFREE(iph); 235ab25eeb5Syz } 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate 239*f4b3ec61Sdh void fr_derefhtable(iph, ifs) 2407c478bd9Sstevel@tonic-gate iphtable_t *iph; 241*f4b3ec61Sdh ipf_stack_t *ifs; 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate iph->iph_ref--; 2447c478bd9Sstevel@tonic-gate if (iph->iph_ref == 0) 245*f4b3ec61Sdh fr_delhtable(iph, ifs); 246*f4b3ec61Sdh } 247*f4b3ec61Sdh 248*f4b3ec61Sdh 249*f4b3ec61Sdh void fr_derefhtent(ipe) 250*f4b3ec61Sdh iphtent_t *ipe; 251*f4b3ec61Sdh { 252*f4b3ec61Sdh ipe->ipe_ref--; 253*f4b3ec61Sdh if (ipe->ipe_ref == 0) { 254*f4b3ec61Sdh KFREE(ipe); 255*f4b3ec61Sdh } 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate 259*f4b3ec61Sdh iphtable_t *fr_findhtable(unit, name, ifs) 2607c478bd9Sstevel@tonic-gate int unit; 2617c478bd9Sstevel@tonic-gate char *name; 262*f4b3ec61Sdh ipf_stack_t *ifs; 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate iphtable_t *iph; 2657c478bd9Sstevel@tonic-gate 266*f4b3ec61Sdh for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next) 2677c478bd9Sstevel@tonic-gate if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate return iph; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate 273*f4b3ec61Sdh size_t fr_flushhtable(op, ifs) 2747c478bd9Sstevel@tonic-gate iplookupflush_t *op; 275*f4b3ec61Sdh ipf_stack_t *ifs; 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate iphtable_t *iph; 278ab25eeb5Syz size_t freed; 279ab25eeb5Syz int i; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate freed = 0; 2827c478bd9Sstevel@tonic-gate 283ab25eeb5Syz for (i = 0; i <= IPL_LOGMAX; i++) { 284ab25eeb5Syz if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 285*f4b3ec61Sdh while ((iph = ifs->ifs_ipf_htables[i]) != NULL) { 286*f4b3ec61Sdh fr_delhtable(iph, ifs); 287ab25eeb5Syz freed++; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate } 290ab25eeb5Syz } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate return freed; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Add an entry to a hash table. 2987c478bd9Sstevel@tonic-gate */ 299*f4b3ec61Sdh int fr_addhtent(iph, ipeo, ifs) 3007c478bd9Sstevel@tonic-gate iphtable_t *iph; 3017c478bd9Sstevel@tonic-gate iphtent_t *ipeo; 302*f4b3ec61Sdh ipf_stack_t *ifs; 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate iphtent_t *ipe; 3057c478bd9Sstevel@tonic-gate u_int hv; 3067c478bd9Sstevel@tonic-gate int bits; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate KMALLOC(ipe, iphtent_t *); 3097c478bd9Sstevel@tonic-gate if (ipe == NULL) 3107c478bd9Sstevel@tonic-gate return -1; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 3137663b816Sml #ifdef USE_INET6 3147663b816Sml if (ipe->ipe_family == AF_INET6) { 3157663b816Sml bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8); 3167663b816Sml hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8), 3177663b816Sml sum4((uint32_t *)ipe->ipe_mask.in6_addr8), 3187663b816Sml iph->iph_size); 3197663b816Sml } else 3207663b816Sml #endif 3217663b816Sml if (ipe->ipe_family == AF_INET) 3227663b816Sml { 3237663b816Sml ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; 3247663b816Sml ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); 3257663b816Sml bits = count4bits(ipe->ipe_mask.in4_addr); 3267663b816Sml ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); 3277663b816Sml 3287663b816Sml hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, 3297663b816Sml iph->iph_size); 3307663b816Sml } else 3317663b816Sml return -1; 3327c478bd9Sstevel@tonic-gate 333*f4b3ec61Sdh ipe->ipe_ref = 1; 3347c478bd9Sstevel@tonic-gate ipe->ipe_next = iph->iph_table[hv]; 3357c478bd9Sstevel@tonic-gate ipe->ipe_pnext = iph->iph_table + hv; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (iph->iph_table[hv] != NULL) 3387c478bd9Sstevel@tonic-gate iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; 3397c478bd9Sstevel@tonic-gate iph->iph_table[hv] = ipe; 340*f4b3ec61Sdh 341*f4b3ec61Sdh ipe->ipe_snext = iph->iph_list; 342*f4b3ec61Sdh ipe->ipe_psnext = &iph->iph_list; 343*f4b3ec61Sdh if (ipe->ipe_next != NULL) 344*f4b3ec61Sdh ipe->ipe_next->ipe_psnext = &ipe->ipe_snext; 345*f4b3ec61Sdh iph->iph_list = ipe; 346*f4b3ec61Sdh 3477663b816Sml #ifdef USE_INET6 3487663b816Sml if (ipe->ipe_family == AF_INET6) { 3497663b816Sml if ((bits >= 0) && (bits != 128)) 3507663b816Sml if (bits >= 96) 3517663b816Sml iph->iph_masks[0] |= 1 << (bits - 96); 3527663b816Sml else if (bits >= 64) 3537663b816Sml iph->iph_masks[1] |= 1 << (bits - 64); 3547663b816Sml else if (bits >= 32) 3557663b816Sml iph->iph_masks[2] |= 1 << (bits - 32); 3567663b816Sml else 3577663b816Sml iph->iph_masks[3] |= 1 << bits; 3587663b816Sml 3597663b816Sml } else 3607663b816Sml #endif 3617663b816Sml { 3627663b816Sml if ((bits >= 0) && (bits != 32)) 3637663b816Sml iph->iph_masks[3] |= 1 << bits; 3647663b816Sml } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate switch (iph->iph_type & ~IPHASH_ANON) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate case IPHASH_GROUPMAP : 3697c478bd9Sstevel@tonic-gate ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, 3707c478bd9Sstevel@tonic-gate iph->iph_flags, IPL_LOGIPF, 371*f4b3ec61Sdh ifs->ifs_fr_active, ifs); 3727c478bd9Sstevel@tonic-gate break; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate default : 3757c478bd9Sstevel@tonic-gate ipe->ipe_ptr = NULL; 3767c478bd9Sstevel@tonic-gate ipe->ipe_value = 0; 3777c478bd9Sstevel@tonic-gate break; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 380*f4b3ec61Sdh ifs->ifs_ipf_nhtnodes[iph->iph_unit]++; 3817663b816Sml 3827c478bd9Sstevel@tonic-gate return 0; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Delete an entry from a hash table. 3887c478bd9Sstevel@tonic-gate */ 389*f4b3ec61Sdh int fr_delhtent(iph, ipe, ifs) 3907c478bd9Sstevel@tonic-gate iphtable_t *iph; 3917c478bd9Sstevel@tonic-gate iphtent_t *ipe; 392*f4b3ec61Sdh ipf_stack_t *ifs; 3937c478bd9Sstevel@tonic-gate { 394*f4b3ec61Sdh if (ipe->ipe_ref != 1) 3957c478bd9Sstevel@tonic-gate return EBUSY; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate *ipe->ipe_pnext = ipe->ipe_next; 3997c478bd9Sstevel@tonic-gate if (ipe->ipe_next != NULL) 4007c478bd9Sstevel@tonic-gate ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate switch (iph->iph_type & ~IPHASH_ANON) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate case IPHASH_GROUPMAP : 4057c478bd9Sstevel@tonic-gate if (ipe->ipe_group != NULL) 406*f4b3ec61Sdh fr_delgroup(ipe->ipe_group, IPL_LOGIPF, 407*f4b3ec61Sdh ifs->ifs_fr_active, ifs); 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate default : 4117c478bd9Sstevel@tonic-gate ipe->ipe_ptr = NULL; 4127c478bd9Sstevel@tonic-gate ipe->ipe_value = 0; 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate KFREE(ipe); 4177c478bd9Sstevel@tonic-gate 418*f4b3ec61Sdh ifs->ifs_ipf_nhtnodes[iph->iph_unit]--; 419*f4b3ec61Sdh 4207c478bd9Sstevel@tonic-gate return 0; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate 424*f4b3ec61Sdh void *fr_iphmfindgroup(tptr, version, aptr, ifs) 425ab25eeb5Syz void *tptr; 4267663b816Sml int version; 427ab25eeb5Syz void *aptr; 428*f4b3ec61Sdh ipf_stack_t *ifs; 4297c478bd9Sstevel@tonic-gate { 4307663b816Sml i6addr_t *addr; 4317c478bd9Sstevel@tonic-gate iphtable_t *iph; 4327c478bd9Sstevel@tonic-gate iphtent_t *ipe; 4337c478bd9Sstevel@tonic-gate void *rval; 4347c478bd9Sstevel@tonic-gate 4357663b816Sml if ((version != 4) 4367663b816Sml #ifdef USE_INET6 4377663b816Sml && (version != 6) 4387663b816Sml #endif 4397663b816Sml ) 4407663b816Sml return NULL; 4417663b816Sml 442*f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 4437c478bd9Sstevel@tonic-gate iph = tptr; 4447c478bd9Sstevel@tonic-gate addr = aptr; 4457c478bd9Sstevel@tonic-gate 4467663b816Sml #ifdef USE_INET6 4477663b816Sml if (version == 6) 4487663b816Sml ipe = fr_iphmfind6(iph, &addr->in6); 4497663b816Sml else 4507663b816Sml #endif 4517663b816Sml if (version == 4) 4527663b816Sml ipe = fr_iphmfind(iph, &addr->in4); 4537663b816Sml else 4547663b816Sml ipe = NULL; 4557c478bd9Sstevel@tonic-gate if (ipe != NULL) 4567c478bd9Sstevel@tonic-gate rval = ipe->ipe_ptr; 4577c478bd9Sstevel@tonic-gate else 4587c478bd9Sstevel@tonic-gate rval = NULL; 459*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 4607c478bd9Sstevel@tonic-gate return rval; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate 464ab25eeb5Syz /* ------------------------------------------------------------------------ */ 465ab25eeb5Syz /* Function: fr_iphmfindip */ 466ab25eeb5Syz /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 467ab25eeb5Syz /* Parameters: tptr(I) - pointer to the pool to search */ 468ab25eeb5Syz /* version(I) - IP protocol version (4 or 6) */ 469ab25eeb5Syz /* aptr(I) - pointer to address information */ 470ab25eeb5Syz /* */ 471ab25eeb5Syz /* Search the hash table for a given address and return a search result. */ 472ab25eeb5Syz /* ------------------------------------------------------------------------ */ 473*f4b3ec61Sdh int fr_iphmfindip(tptr, version, aptr, ifs) 4747c478bd9Sstevel@tonic-gate void *tptr, *aptr; 4757c478bd9Sstevel@tonic-gate int version; 476*f4b3ec61Sdh ipf_stack_t *ifs; 4777c478bd9Sstevel@tonic-gate { 4787663b816Sml i6addr_t *addr; 4797c478bd9Sstevel@tonic-gate iphtable_t *iph; 4807c478bd9Sstevel@tonic-gate iphtent_t *ipe; 4817c478bd9Sstevel@tonic-gate int rval; 4827c478bd9Sstevel@tonic-gate 483ab25eeb5Syz if ((version != 4) 484ab25eeb5Syz #ifdef USE_INET6 485ab25eeb5Syz && (version != 6) 486ab25eeb5Syz #endif 487ab25eeb5Syz ) 488ab25eeb5Syz return -1; 489ab25eeb5Syz 4907c478bd9Sstevel@tonic-gate if (tptr == NULL || aptr == NULL) 491ab25eeb5Syz return -1; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate iph = tptr; 4947c478bd9Sstevel@tonic-gate addr = aptr; 4957c478bd9Sstevel@tonic-gate 496*f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 4977663b816Sml #ifdef USE_INET6 4987663b816Sml if (version == 6) 4997663b816Sml ipe = fr_iphmfind6(iph, &addr->in6); 5007663b816Sml else 5017663b816Sml #endif 5027663b816Sml if (version == 4) 5037663b816Sml ipe = fr_iphmfind(iph, &addr->in4); 5047663b816Sml else 5057663b816Sml ipe = NULL; 5067c478bd9Sstevel@tonic-gate if (ipe != NULL) 5077c478bd9Sstevel@tonic-gate rval = 0; 5087c478bd9Sstevel@tonic-gate else 5097c478bd9Sstevel@tonic-gate rval = 1; 510*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 5117c478bd9Sstevel@tonic-gate return rval; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* Locks: ip_poolrw */ 5167c478bd9Sstevel@tonic-gate static iphtent_t *fr_iphmfind(iph, addr) 5177c478bd9Sstevel@tonic-gate iphtable_t *iph; 5187c478bd9Sstevel@tonic-gate struct in_addr *addr; 5197c478bd9Sstevel@tonic-gate { 5207c478bd9Sstevel@tonic-gate u_32_t hmsk, msk, ips; 5217c478bd9Sstevel@tonic-gate iphtent_t *ipe; 5227c478bd9Sstevel@tonic-gate u_int hv; 5237c478bd9Sstevel@tonic-gate 5247663b816Sml hmsk = iph->iph_masks[3]; 5257c478bd9Sstevel@tonic-gate msk = 0xffffffff; 5267c478bd9Sstevel@tonic-gate maskloop: 5277c478bd9Sstevel@tonic-gate ips = ntohl(addr->s_addr) & msk; 5287c478bd9Sstevel@tonic-gate hv = IPE_HASH_FN(ips, msk, iph->iph_size); 5297c478bd9Sstevel@tonic-gate for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 5307c478bd9Sstevel@tonic-gate if (ipe->ipe_mask.in4_addr != msk || 5317c478bd9Sstevel@tonic-gate ipe->ipe_addr.in4_addr != ips) { 5327c478bd9Sstevel@tonic-gate continue; 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate break; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if ((ipe == NULL) && (hmsk != 0)) { 5387c478bd9Sstevel@tonic-gate while (hmsk != 0) { 5397c478bd9Sstevel@tonic-gate msk <<= 1; 5407c478bd9Sstevel@tonic-gate if (hmsk & 0x80000000) 5417c478bd9Sstevel@tonic-gate break; 5427c478bd9Sstevel@tonic-gate hmsk <<= 1; 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate if (hmsk != 0) { 5457c478bd9Sstevel@tonic-gate hmsk <<= 1; 5467c478bd9Sstevel@tonic-gate goto maskloop; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate } 5497663b816Sml return ipe; 5507663b816Sml } 5517663b816Sml 5527663b816Sml 5537663b816Sml #ifdef USE_INET6 5547663b816Sml /* Locks: ip_poolrw */ 5557663b816Sml static iphtent_t *fr_iphmfind6(iph, addr) 5567663b816Sml iphtable_t *iph; 5577663b816Sml struct in6_addr *addr; 5587663b816Sml { 5597663b816Sml u_32_t hmsk[4], msk[4], ips[4], *and; 5607663b816Sml iphtent_t *ipe; 5617663b816Sml u_int hv; 5627663b816Sml 5637663b816Sml hmsk[0] = iph->iph_masks[0]; 5647663b816Sml hmsk[1] = iph->iph_masks[1]; 5657663b816Sml hmsk[2] = iph->iph_masks[2]; 5667663b816Sml hmsk[3] = iph->iph_masks[3]; 5677663b816Sml 5687663b816Sml msk[0] = 0xffffffff; 5697663b816Sml msk[1] = 0xffffffff; 5707663b816Sml msk[2] = 0xffffffff; 5717663b816Sml msk[3] = 0xffffffff; 5727663b816Sml maskloop: 5737663b816Sml and = (u_32_t *)addr->s6_addr; 5747663b816Sml ips[0] = *and & msk[0]; 5757663b816Sml ips[1] = *(and + 1) & msk[1]; 5767663b816Sml ips[2] = *(and + 2) & msk[2]; 5777663b816Sml ips[3] = *(and + 3) & msk[3]; 5787663b816Sml 5797663b816Sml hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk), 5807663b816Sml iph->iph_size); 5817663b816Sml for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 5827663b816Sml if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) || 5837663b816Sml bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16)) 5847663b816Sml continue; 5857663b816Sml break; 5867663b816Sml } 5877663b816Sml 5887663b816Sml if ((ipe == NULL) && ((hmsk[0] != 0) || 5897663b816Sml (hmsk[1] != 0) || 5907663b816Sml (hmsk[2] != 0) || 5917663b816Sml (hmsk[3] != 0) )) { 5927663b816Sml while ((hmsk[0] != 0) && (hmsk[1] != 0) && 5937663b816Sml (hmsk[2] != 0) && (hmsk[3] != 0)) { 5947663b816Sml left_shift_ipv6((char *)msk); 5957663b816Sml if (hmsk[0] & 0x80000000) 5967663b816Sml break; 5977663b816Sml left_shift_ipv6((char *)hmsk); 5987663b816Sml } 5997663b816Sml if ((hmsk[0] != 0) && (hmsk[1] != 0) && 6007663b816Sml (hmsk[2] != 0) && (hmsk[3] != 0)) { 6017663b816Sml left_shift_ipv6((char *)hmsk); 6027663b816Sml goto maskloop; 6037663b816Sml } 6047663b816Sml } 6057c478bd9Sstevel@tonic-gate return ipe; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087663b816Sml 6097663b816Sml /* 6107663b816Sml * sum4: ipv6 add -> 4 bytes values 6117663b816Sml */ 6127663b816Sml static uint32_t sum4(add) 6137663b816Sml uint32_t *add; 6147663b816Sml { 6157663b816Sml return (*add + *(add + 1) + *(add + 2) + *(add + 3)); 6167663b816Sml } 6177663b816Sml 6187663b816Sml /* 6197663b816Sml * left shift on 128 bits 6207663b816Sml */ 6217663b816Sml static void left_shift_ipv6(data) 6227663b816Sml char *data; 6237663b816Sml { 6247663b816Sml u_32_t *sd; 6257663b816Sml 6267663b816Sml sd = (u_32_t *)data; 6277663b816Sml sd[0] <<= 1; 6287663b816Sml if (sd[1] >= 0x80000000) 6297663b816Sml sd[0] += 1; 6307663b816Sml 6317663b816Sml sd[1] <<= 1; 6327663b816Sml if (sd[2] >= 0x80000000) 6337663b816Sml sd[1] += 1; 6347663b816Sml 6357663b816Sml sd[2] <<= 1; 6367663b816Sml if (sd[3] >= 0x80000000) 6377663b816Sml sd[2] += 1; 6387663b816Sml 6397663b816Sml sd[3] <<= 1; 6407663b816Sml } 6417663b816Sml #endif 642*f4b3ec61Sdh 643*f4b3ec61Sdh int fr_htable_getnext(token, ilp, ifs) 644*f4b3ec61Sdh ipftoken_t *token; 645*f4b3ec61Sdh ipflookupiter_t *ilp; 646*f4b3ec61Sdh ipf_stack_t *ifs; 647*f4b3ec61Sdh { 648*f4b3ec61Sdh iphtent_t *node, zn, *nextnode; 649*f4b3ec61Sdh iphtable_t *iph, zp, *nextiph; 650*f4b3ec61Sdh int err; 651*f4b3ec61Sdh 652*f4b3ec61Sdh err = 0; 653*f4b3ec61Sdh iph = NULL; 654*f4b3ec61Sdh node = NULL; 655*f4b3ec61Sdh nextiph = NULL; 656*f4b3ec61Sdh nextnode = NULL; 657*f4b3ec61Sdh 658*f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 659*f4b3ec61Sdh 660*f4b3ec61Sdh switch (ilp->ili_otype) 661*f4b3ec61Sdh { 662*f4b3ec61Sdh case IPFLOOKUPITER_LIST : 663*f4b3ec61Sdh iph = token->ipt_data; 664*f4b3ec61Sdh if (iph == NULL) { 665*f4b3ec61Sdh nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit]; 666*f4b3ec61Sdh } else { 667*f4b3ec61Sdh nextiph = iph->iph_next; 668*f4b3ec61Sdh } 669*f4b3ec61Sdh 670*f4b3ec61Sdh if (nextiph != NULL) { 671*f4b3ec61Sdh if (nextiph->iph_next == NULL) 672*f4b3ec61Sdh token->ipt_alive = 0; 673*f4b3ec61Sdh else { 674*f4b3ec61Sdh ATOMIC_INC(nextiph->iph_ref); 675*f4b3ec61Sdh } 676*f4b3ec61Sdh } else { 677*f4b3ec61Sdh bzero((char *)&zp, sizeof(zp)); 678*f4b3ec61Sdh nextiph = &zp; 679*f4b3ec61Sdh } 680*f4b3ec61Sdh break; 681*f4b3ec61Sdh 682*f4b3ec61Sdh case IPFLOOKUPITER_NODE : 683*f4b3ec61Sdh node = token->ipt_data; 684*f4b3ec61Sdh if (node == NULL) { 685*f4b3ec61Sdh iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs); 686*f4b3ec61Sdh if (iph == NULL) 687*f4b3ec61Sdh err = ESRCH; 688*f4b3ec61Sdh else { 689*f4b3ec61Sdh nextnode = iph->iph_list; 690*f4b3ec61Sdh } 691*f4b3ec61Sdh } else { 692*f4b3ec61Sdh nextnode = node->ipe_snext; 693*f4b3ec61Sdh } 694*f4b3ec61Sdh 695*f4b3ec61Sdh if (nextnode != NULL) { 696*f4b3ec61Sdh if (nextnode->ipe_snext == NULL) 697*f4b3ec61Sdh token->ipt_alive = 0; 698*f4b3ec61Sdh else { 699*f4b3ec61Sdh ATOMIC_INC(nextnode->ipe_ref); 700*f4b3ec61Sdh } 701*f4b3ec61Sdh } else { 702*f4b3ec61Sdh bzero((char *)&zn, sizeof(zn)); 703*f4b3ec61Sdh nextnode = &zn; 704*f4b3ec61Sdh } 705*f4b3ec61Sdh break; 706*f4b3ec61Sdh default : 707*f4b3ec61Sdh err = EINVAL; 708*f4b3ec61Sdh break; 709*f4b3ec61Sdh } 710*f4b3ec61Sdh 711*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 712*f4b3ec61Sdh if (err != 0) 713*f4b3ec61Sdh return err; 714*f4b3ec61Sdh 715*f4b3ec61Sdh switch (ilp->ili_otype) 716*f4b3ec61Sdh { 717*f4b3ec61Sdh case IPFLOOKUPITER_LIST : 718*f4b3ec61Sdh if (iph != NULL) { 719*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 720*f4b3ec61Sdh fr_derefhtable(iph, ifs); 721*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 722*f4b3ec61Sdh } 723*f4b3ec61Sdh token->ipt_data = nextiph; 724*f4b3ec61Sdh err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 725*f4b3ec61Sdh if (err != 0) 726*f4b3ec61Sdh err = EFAULT; 727*f4b3ec61Sdh break; 728*f4b3ec61Sdh 729*f4b3ec61Sdh case IPFLOOKUPITER_NODE : 730*f4b3ec61Sdh if (node != NULL) { 731*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 732*f4b3ec61Sdh fr_derefhtent(node); 733*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 734*f4b3ec61Sdh } 735*f4b3ec61Sdh token->ipt_data = nextnode; 736*f4b3ec61Sdh err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 737*f4b3ec61Sdh if (err != 0) 738*f4b3ec61Sdh err = EFAULT; 739*f4b3ec61Sdh break; 740*f4b3ec61Sdh } 741*f4b3ec61Sdh 742*f4b3ec61Sdh return err; 743*f4b3ec61Sdh } 744*f4b3ec61Sdh 745*f4b3ec61Sdh 746*f4b3ec61Sdh void fr_htable_iterderef(otype, unit, data, ifs) 747*f4b3ec61Sdh u_int otype; 748*f4b3ec61Sdh int unit; 749*f4b3ec61Sdh void *data; 750*f4b3ec61Sdh ipf_stack_t *ifs; 751*f4b3ec61Sdh { 752*f4b3ec61Sdh 753*f4b3ec61Sdh if (data == NULL) 754*f4b3ec61Sdh return; 755*f4b3ec61Sdh 756*f4b3ec61Sdh if (unit < 0 || unit > IPL_LOGMAX) 757*f4b3ec61Sdh return; 758*f4b3ec61Sdh 759*f4b3ec61Sdh switch (otype) 760*f4b3ec61Sdh { 761*f4b3ec61Sdh case IPFLOOKUPITER_LIST : 762*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 763*f4b3ec61Sdh fr_derefhtable((iphtable_t *)data, ifs); 764*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 765*f4b3ec61Sdh break; 766*f4b3ec61Sdh 767*f4b3ec61Sdh case IPFLOOKUPITER_NODE : 768*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 769*f4b3ec61Sdh fr_derefhtent((iphtent_t *)data); 770*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 771*f4b3ec61Sdh break; 772*f4b3ec61Sdh default : 773*f4b3ec61Sdh break; 774*f4b3ec61Sdh } 775*f4b3ec61Sdh } 7767c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOOKUP */ 777