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*de22af4eSJohn Ojemann * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 77c478bd9Sstevel@tonic-gate */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 107c478bd9Sstevel@tonic-gate # undef KERNEL 117c478bd9Sstevel@tonic-gate # undef _KERNEL 127c478bd9Sstevel@tonic-gate # define KERNEL 1 137c478bd9Sstevel@tonic-gate # define _KERNEL 1 147c478bd9Sstevel@tonic-gate #endif 157c478bd9Sstevel@tonic-gate #include <sys/param.h> 167c478bd9Sstevel@tonic-gate #include <sys/types.h> 177c478bd9Sstevel@tonic-gate #include <sys/errno.h> 187c478bd9Sstevel@tonic-gate #include <sys/time.h> 197c478bd9Sstevel@tonic-gate #include <sys/file.h> 207c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 217c478bd9Sstevel@tonic-gate # include <stdlib.h> 227c478bd9Sstevel@tonic-gate # include <string.h> 237c478bd9Sstevel@tonic-gate # define _KERNEL 247c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 257c478bd9Sstevel@tonic-gate struct file; 267c478bd9Sstevel@tonic-gate # endif 277c478bd9Sstevel@tonic-gate # include <sys/uio.h> 287c478bd9Sstevel@tonic-gate # undef _KERNEL 297c478bd9Sstevel@tonic-gate #endif 307c478bd9Sstevel@tonic-gate #include <sys/socket.h> 317c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 327c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 337c478bd9Sstevel@tonic-gate #endif 347c478bd9Sstevel@tonic-gate #if defined(__FreeBSD__) 357c478bd9Sstevel@tonic-gate # include <sys/cdefs.h> 367c478bd9Sstevel@tonic-gate # include <sys/proc.h> 377c478bd9Sstevel@tonic-gate #endif 38ab25eeb5Syz #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ 39ab25eeb5Syz !defined(linux) 407c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 417c478bd9Sstevel@tonic-gate #endif 427c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 437c478bd9Sstevel@tonic-gate # include <sys/systm.h> 447c478bd9Sstevel@tonic-gate #else 457c478bd9Sstevel@tonic-gate # include <stdio.h> 467c478bd9Sstevel@tonic-gate #endif 477c478bd9Sstevel@tonic-gate #include <netinet/in.h> 487c478bd9Sstevel@tonic-gate #include <net/if.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h" 517c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 527c478bd9Sstevel@tonic-gate #include "netinet/ip_lookup.h" 537c478bd9Sstevel@tonic-gate #include "netinet/ip_htable.h" 54f4b3ec61Sdh #include "netinet/ipf_stack.h" 55ab25eeb5Syz /* END OF INCLUDES */ 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #if !defined(lint) 58ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $"; 597c478bd9Sstevel@tonic-gate #endif 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 627c478bd9Sstevel@tonic-gate static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); 637663b816Sml #ifdef USE_INET6 647663b816Sml static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *)); 657663b816Sml static uint32_t sum4(uint32_t *); 667663b816Sml static void left_shift_ipv6 __P((char *)); 677663b816Sml #endif 687c478bd9Sstevel@tonic-gate 69f4b3ec61Sdh void fr_htable_unload(ifs) 70f4b3ec61Sdh ipf_stack_t *ifs; 717c478bd9Sstevel@tonic-gate { 727c478bd9Sstevel@tonic-gate iplookupflush_t fop; 73ab25eeb5Syz 74ab25eeb5Syz fop.iplf_unit = IPL_LOGALL; 75f4b3ec61Sdh (void)fr_flushhtable(&fop, ifs); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 78ab25eeb5Syz 79f4b3ec61Sdh int fr_gethtablestat(op, ifs) 807663b816Sml iplookupop_t *op; 81f4b3ec61Sdh ipf_stack_t *ifs; 827663b816Sml { 837663b816Sml iphtstat_t stats; 847663b816Sml 857663b816Sml if (op->iplo_size != sizeof(stats)) 867663b816Sml return EINVAL; 877663b816Sml 88f4b3ec61Sdh stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit]; 89f4b3ec61Sdh stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit]; 90f4b3ec61Sdh stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit]; 91f4b3ec61Sdh stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit]; 927663b816Sml 937663b816Sml return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 947663b816Sml 957663b816Sml } 967663b816Sml 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Create a new hash table using the template passed. 1007c478bd9Sstevel@tonic-gate */ 101f4b3ec61Sdh int fr_newhtable(op, ifs) 1027c478bd9Sstevel@tonic-gate iplookupop_t *op; 103f4b3ec61Sdh ipf_stack_t *ifs; 1047c478bd9Sstevel@tonic-gate { 1057c478bd9Sstevel@tonic-gate iphtable_t *iph, *oiph; 1067c478bd9Sstevel@tonic-gate char name[FR_GROUPLEN]; 1077c478bd9Sstevel@tonic-gate int err, i, unit; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate KMALLOC(iph, iphtable_t *); 110ab25eeb5Syz if (iph == NULL) { 111f4b3ec61Sdh ifs->ifs_ipht_nomem[op->iplo_unit]++; 112ab25eeb5Syz return ENOMEM; 113ab25eeb5Syz } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); 1167c478bd9Sstevel@tonic-gate if (err != 0) { 1177c478bd9Sstevel@tonic-gate KFREE(iph); 1187c478bd9Sstevel@tonic-gate return EFAULT; 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate unit = op->iplo_unit; 1227c478bd9Sstevel@tonic-gate if (iph->iph_unit != unit) { 1237c478bd9Sstevel@tonic-gate KFREE(iph); 1247c478bd9Sstevel@tonic-gate return EINVAL; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate if ((op->iplo_arg & IPHASH_ANON) == 0) { 128f4b3ec61Sdh if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) { 1297c478bd9Sstevel@tonic-gate KFREE(iph); 1307c478bd9Sstevel@tonic-gate return EEXIST; 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate } else { 1337c478bd9Sstevel@tonic-gate i = IPHASH_ANON; 1347c478bd9Sstevel@tonic-gate do { 1357c478bd9Sstevel@tonic-gate i++; 136ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL) 137ab25eeb5Syz (void)SNPRINTF(name, sizeof(name), "%u", i); 138ab25eeb5Syz #else 1397c478bd9Sstevel@tonic-gate (void)sprintf(name, "%u", i); 140ab25eeb5Syz #endif 141f4b3ec61Sdh for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL; 1427c478bd9Sstevel@tonic-gate oiph = oiph->iph_next) 1437c478bd9Sstevel@tonic-gate if (strncmp(oiph->iph_name, name, 1447c478bd9Sstevel@tonic-gate sizeof(oiph->iph_name)) == 0) 1457c478bd9Sstevel@tonic-gate break; 1467c478bd9Sstevel@tonic-gate } while (oiph != NULL); 1477c478bd9Sstevel@tonic-gate (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 1487c478bd9Sstevel@tonic-gate err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); 1497c478bd9Sstevel@tonic-gate if (err != 0) { 1507c478bd9Sstevel@tonic-gate KFREE(iph); 1517c478bd9Sstevel@tonic-gate return EFAULT; 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate iph->iph_type |= IPHASH_ANON; 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate KMALLOCS(iph->iph_table, iphtent_t **, 1577c478bd9Sstevel@tonic-gate iph->iph_size * sizeof(*iph->iph_table)); 1587c478bd9Sstevel@tonic-gate if (iph->iph_table == NULL) { 1597c478bd9Sstevel@tonic-gate KFREE(iph); 160f4b3ec61Sdh ifs->ifs_ipht_nomem[unit]++; 1617c478bd9Sstevel@tonic-gate return ENOMEM; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 1657663b816Sml iph->iph_masks[0] = 0; 1667663b816Sml iph->iph_masks[1] = 0; 1677663b816Sml iph->iph_masks[2] = 0; 1687663b816Sml iph->iph_masks[3] = 0; 169f4b3ec61Sdh iph->iph_list = NULL; 1707c478bd9Sstevel@tonic-gate 171f4b3ec61Sdh iph->iph_ref = 1; 172f4b3ec61Sdh iph->iph_next = ifs->ifs_ipf_htables[unit]; 173f4b3ec61Sdh iph->iph_pnext = &ifs->ifs_ipf_htables[unit]; 174f4b3ec61Sdh if (ifs->ifs_ipf_htables[unit] != NULL) 175f4b3ec61Sdh ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next; 176f4b3ec61Sdh ifs->ifs_ipf_htables[unit] = iph; 1777663b816Sml 178f4b3ec61Sdh ifs->ifs_ipf_nhtables[unit]++; 1797663b816Sml 1807c478bd9Sstevel@tonic-gate return 0; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate */ 186f4b3ec61Sdh int fr_removehtable(op, ifs) 1877c478bd9Sstevel@tonic-gate iplookupop_t *op; 188f4b3ec61Sdh ipf_stack_t *ifs; 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate iphtable_t *iph; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate 193f4b3ec61Sdh iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs); 1947c478bd9Sstevel@tonic-gate if (iph == NULL) 1957c478bd9Sstevel@tonic-gate return ESRCH; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if (iph->iph_unit != op->iplo_unit) { 1987c478bd9Sstevel@tonic-gate return EINVAL; 1997c478bd9Sstevel@tonic-gate } 200f4b3ec61Sdh 201f4b3ec61Sdh if (iph->iph_ref != 1) { 2027c478bd9Sstevel@tonic-gate return EBUSY; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 205f4b3ec61Sdh fr_delhtable(iph, ifs); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate return 0; 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate 211f4b3ec61Sdh void fr_delhtable(iph, ifs) 2127c478bd9Sstevel@tonic-gate iphtable_t *iph; 213f4b3ec61Sdh ipf_stack_t *ifs; 2147c478bd9Sstevel@tonic-gate { 215ab25eeb5Syz iphtent_t *ipe; 216ab25eeb5Syz int i; 217ab25eeb5Syz 218ab25eeb5Syz for (i = 0; i < iph->iph_size; i++) 219ab25eeb5Syz while ((ipe = iph->iph_table[i]) != NULL) 220f4b3ec61Sdh if (fr_delhtent(iph, ipe, ifs) != 0) 221ab25eeb5Syz return; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate *iph->iph_pnext = iph->iph_next; 2247c478bd9Sstevel@tonic-gate if (iph->iph_next != NULL) 2257c478bd9Sstevel@tonic-gate iph->iph_next->iph_pnext = iph->iph_pnext; 2267c478bd9Sstevel@tonic-gate 227f4b3ec61Sdh ifs->ifs_ipf_nhtables[iph->iph_unit]--; 228ab25eeb5Syz 229f4b3ec61Sdh if (iph->iph_ref == 1) { 230ab25eeb5Syz KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 231ab25eeb5Syz KFREE(iph); 232ab25eeb5Syz } 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate 236f4b3ec61Sdh void fr_derefhtable(iph, ifs) 2377c478bd9Sstevel@tonic-gate iphtable_t *iph; 238f4b3ec61Sdh ipf_stack_t *ifs; 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate iph->iph_ref--; 2417c478bd9Sstevel@tonic-gate if (iph->iph_ref == 0) 242f4b3ec61Sdh fr_delhtable(iph, ifs); 243f4b3ec61Sdh } 244f4b3ec61Sdh 245f4b3ec61Sdh 246f4b3ec61Sdh void fr_derefhtent(ipe) 247f4b3ec61Sdh iphtent_t *ipe; 248f4b3ec61Sdh { 249f4b3ec61Sdh ipe->ipe_ref--; 250f4b3ec61Sdh if (ipe->ipe_ref == 0) { 251f4b3ec61Sdh KFREE(ipe); 252f4b3ec61Sdh } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate 256f4b3ec61Sdh iphtable_t *fr_findhtable(unit, name, ifs) 2577c478bd9Sstevel@tonic-gate int unit; 2587c478bd9Sstevel@tonic-gate char *name; 259f4b3ec61Sdh ipf_stack_t *ifs; 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate iphtable_t *iph; 2627c478bd9Sstevel@tonic-gate 263f4b3ec61Sdh for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next) 2647c478bd9Sstevel@tonic-gate if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) 2657c478bd9Sstevel@tonic-gate break; 2667c478bd9Sstevel@tonic-gate return iph; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate 270f4b3ec61Sdh size_t fr_flushhtable(op, ifs) 2717c478bd9Sstevel@tonic-gate iplookupflush_t *op; 272f4b3ec61Sdh ipf_stack_t *ifs; 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate iphtable_t *iph; 275ab25eeb5Syz size_t freed; 276ab25eeb5Syz int i; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate freed = 0; 2797c478bd9Sstevel@tonic-gate 280ab25eeb5Syz for (i = 0; i <= IPL_LOGMAX; i++) { 281ab25eeb5Syz if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 282f4b3ec61Sdh while ((iph = ifs->ifs_ipf_htables[i]) != NULL) { 283f4b3ec61Sdh fr_delhtable(iph, ifs); 284ab25eeb5Syz freed++; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 287ab25eeb5Syz } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate return freed; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Add an entry to a hash table. 2957c478bd9Sstevel@tonic-gate */ 296f4b3ec61Sdh int fr_addhtent(iph, ipeo, ifs) 2977c478bd9Sstevel@tonic-gate iphtable_t *iph; 2987c478bd9Sstevel@tonic-gate iphtent_t *ipeo; 299f4b3ec61Sdh ipf_stack_t *ifs; 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate iphtent_t *ipe; 3027c478bd9Sstevel@tonic-gate u_int hv; 3037c478bd9Sstevel@tonic-gate int bits; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate KMALLOC(ipe, iphtent_t *); 3067c478bd9Sstevel@tonic-gate if (ipe == NULL) 3077c478bd9Sstevel@tonic-gate return -1; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 3107663b816Sml #ifdef USE_INET6 3117663b816Sml if (ipe->ipe_family == AF_INET6) { 3127663b816Sml bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8); 3137663b816Sml hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8), 3147663b816Sml sum4((uint32_t *)ipe->ipe_mask.in6_addr8), 3157663b816Sml iph->iph_size); 3167663b816Sml } else 3177663b816Sml #endif 3187663b816Sml if (ipe->ipe_family == AF_INET) 3197663b816Sml { 3207663b816Sml ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; 3217663b816Sml ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); 3227663b816Sml bits = count4bits(ipe->ipe_mask.in4_addr); 3237663b816Sml ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); 3247663b816Sml 3257663b816Sml hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, 3267663b816Sml iph->iph_size); 3277663b816Sml } else 3287663b816Sml return -1; 3297c478bd9Sstevel@tonic-gate 330f4b3ec61Sdh ipe->ipe_ref = 1; 3317c478bd9Sstevel@tonic-gate ipe->ipe_next = iph->iph_table[hv]; 3327c478bd9Sstevel@tonic-gate ipe->ipe_pnext = iph->iph_table + hv; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (iph->iph_table[hv] != NULL) 3357c478bd9Sstevel@tonic-gate iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; 3367c478bd9Sstevel@tonic-gate iph->iph_table[hv] = ipe; 337f4b3ec61Sdh 338f4b3ec61Sdh ipe->ipe_snext = iph->iph_list; 339f4b3ec61Sdh ipe->ipe_psnext = &iph->iph_list; 340f4b3ec61Sdh if (ipe->ipe_next != NULL) 341f4b3ec61Sdh ipe->ipe_next->ipe_psnext = &ipe->ipe_snext; 342f4b3ec61Sdh iph->iph_list = ipe; 343f4b3ec61Sdh 3447663b816Sml #ifdef USE_INET6 3457663b816Sml if (ipe->ipe_family == AF_INET6) { 3467663b816Sml if ((bits >= 0) && (bits != 128)) 3477663b816Sml if (bits >= 96) 3487663b816Sml iph->iph_masks[0] |= 1 << (bits - 96); 3497663b816Sml else if (bits >= 64) 3507663b816Sml iph->iph_masks[1] |= 1 << (bits - 64); 3517663b816Sml else if (bits >= 32) 3527663b816Sml iph->iph_masks[2] |= 1 << (bits - 32); 3537663b816Sml else 3547663b816Sml iph->iph_masks[3] |= 1 << bits; 3557663b816Sml 3567663b816Sml } else 3577663b816Sml #endif 3587663b816Sml { 3597663b816Sml if ((bits >= 0) && (bits != 32)) 3607663b816Sml iph->iph_masks[3] |= 1 << bits; 3617663b816Sml } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate switch (iph->iph_type & ~IPHASH_ANON) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate case IPHASH_GROUPMAP : 3667c478bd9Sstevel@tonic-gate ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, 3677c478bd9Sstevel@tonic-gate iph->iph_flags, IPL_LOGIPF, 368f4b3ec61Sdh ifs->ifs_fr_active, ifs); 3697c478bd9Sstevel@tonic-gate break; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate default : 3727c478bd9Sstevel@tonic-gate ipe->ipe_ptr = NULL; 3737c478bd9Sstevel@tonic-gate ipe->ipe_value = 0; 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 377f4b3ec61Sdh ifs->ifs_ipf_nhtnodes[iph->iph_unit]++; 3787663b816Sml 3797c478bd9Sstevel@tonic-gate return 0; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Delete an entry from a hash table. 3857c478bd9Sstevel@tonic-gate */ 386f4b3ec61Sdh int fr_delhtent(iph, ipe, ifs) 3877c478bd9Sstevel@tonic-gate iphtable_t *iph; 3887c478bd9Sstevel@tonic-gate iphtent_t *ipe; 389f4b3ec61Sdh ipf_stack_t *ifs; 3907c478bd9Sstevel@tonic-gate { 391f4b3ec61Sdh if (ipe->ipe_ref != 1) 3927c478bd9Sstevel@tonic-gate return EBUSY; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate *ipe->ipe_pnext = ipe->ipe_next; 3967c478bd9Sstevel@tonic-gate if (ipe->ipe_next != NULL) 3977c478bd9Sstevel@tonic-gate ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate switch (iph->iph_type & ~IPHASH_ANON) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate case IPHASH_GROUPMAP : 4027c478bd9Sstevel@tonic-gate if (ipe->ipe_group != NULL) 403f4b3ec61Sdh fr_delgroup(ipe->ipe_group, IPL_LOGIPF, 404f4b3ec61Sdh ifs->ifs_fr_active, ifs); 4057c478bd9Sstevel@tonic-gate break; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate default : 4087c478bd9Sstevel@tonic-gate ipe->ipe_ptr = NULL; 4097c478bd9Sstevel@tonic-gate ipe->ipe_value = 0; 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate KFREE(ipe); 4147c478bd9Sstevel@tonic-gate 415f4b3ec61Sdh ifs->ifs_ipf_nhtnodes[iph->iph_unit]--; 416f4b3ec61Sdh 4177c478bd9Sstevel@tonic-gate return 0; 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate 421f4b3ec61Sdh void *fr_iphmfindgroup(tptr, version, aptr, ifs) 422ab25eeb5Syz void *tptr; 4237663b816Sml int version; 424ab25eeb5Syz void *aptr; 425f4b3ec61Sdh ipf_stack_t *ifs; 4267c478bd9Sstevel@tonic-gate { 4277663b816Sml i6addr_t *addr; 4287c478bd9Sstevel@tonic-gate iphtable_t *iph; 4297c478bd9Sstevel@tonic-gate iphtent_t *ipe; 4307c478bd9Sstevel@tonic-gate void *rval; 4317c478bd9Sstevel@tonic-gate 4327663b816Sml if ((version != 4) 4337663b816Sml #ifdef USE_INET6 4347663b816Sml && (version != 6) 4357663b816Sml #endif 4367663b816Sml ) 4377663b816Sml return NULL; 4387663b816Sml 439f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 4407c478bd9Sstevel@tonic-gate iph = tptr; 4417c478bd9Sstevel@tonic-gate addr = aptr; 4427c478bd9Sstevel@tonic-gate 4437663b816Sml #ifdef USE_INET6 4447663b816Sml if (version == 6) 4457663b816Sml ipe = fr_iphmfind6(iph, &addr->in6); 4467663b816Sml else 4477663b816Sml #endif 4487663b816Sml if (version == 4) 4497663b816Sml ipe = fr_iphmfind(iph, &addr->in4); 4507663b816Sml else 4517663b816Sml ipe = NULL; 4527c478bd9Sstevel@tonic-gate if (ipe != NULL) 4537c478bd9Sstevel@tonic-gate rval = ipe->ipe_ptr; 4547c478bd9Sstevel@tonic-gate else 4557c478bd9Sstevel@tonic-gate rval = NULL; 456f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 4577c478bd9Sstevel@tonic-gate return rval; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate 461ab25eeb5Syz /* ------------------------------------------------------------------------ */ 462ab25eeb5Syz /* Function: fr_iphmfindip */ 463ab25eeb5Syz /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 464ab25eeb5Syz /* Parameters: tptr(I) - pointer to the pool to search */ 465ab25eeb5Syz /* version(I) - IP protocol version (4 or 6) */ 466ab25eeb5Syz /* aptr(I) - pointer to address information */ 467*de22af4eSJohn Ojemann /* fin - pointer to packet information */ 468*de22af4eSJohn Ojemann /* ifs - ipf stack instance */ 469ab25eeb5Syz /* */ 470ab25eeb5Syz /* Search the hash table for a given address and return a search result. */ 471ab25eeb5Syz /* ------------------------------------------------------------------------ */ 472*de22af4eSJohn Ojemann int fr_iphmfindip(tptr, version, aptr, fin, ifs) 4737c478bd9Sstevel@tonic-gate void *tptr, *aptr; 4747c478bd9Sstevel@tonic-gate int version; 475*de22af4eSJohn Ojemann fr_info_t *fin; 476f4b3ec61Sdh 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 496f4b3ec61Sdh 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; 506*de22af4eSJohn Ojemann if (ipe != NULL) { 507*de22af4eSJohn Ojemann ipe->ipe_hits++; 508*de22af4eSJohn Ojemann ipe->ipe_bytes += fin->fin_plen; 5097c478bd9Sstevel@tonic-gate rval = 0; 510*de22af4eSJohn Ojemann } else { 5117c478bd9Sstevel@tonic-gate rval = 1; 512*de22af4eSJohn Ojemann } 513f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 5147c478bd9Sstevel@tonic-gate return rval; 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* Locks: ip_poolrw */ 5197c478bd9Sstevel@tonic-gate static iphtent_t *fr_iphmfind(iph, addr) 5207c478bd9Sstevel@tonic-gate iphtable_t *iph; 5217c478bd9Sstevel@tonic-gate struct in_addr *addr; 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate u_32_t hmsk, msk, ips; 5247c478bd9Sstevel@tonic-gate iphtent_t *ipe; 5257c478bd9Sstevel@tonic-gate u_int hv; 5267c478bd9Sstevel@tonic-gate 5277663b816Sml hmsk = iph->iph_masks[3]; 5287c478bd9Sstevel@tonic-gate msk = 0xffffffff; 5297c478bd9Sstevel@tonic-gate maskloop: 5307c478bd9Sstevel@tonic-gate ips = ntohl(addr->s_addr) & msk; 5317c478bd9Sstevel@tonic-gate hv = IPE_HASH_FN(ips, msk, iph->iph_size); 5327c478bd9Sstevel@tonic-gate for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 5337c478bd9Sstevel@tonic-gate if (ipe->ipe_mask.in4_addr != msk || 5347c478bd9Sstevel@tonic-gate ipe->ipe_addr.in4_addr != ips) { 5357c478bd9Sstevel@tonic-gate continue; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate break; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if ((ipe == NULL) && (hmsk != 0)) { 5417c478bd9Sstevel@tonic-gate while (hmsk != 0) { 5427c478bd9Sstevel@tonic-gate msk <<= 1; 5437c478bd9Sstevel@tonic-gate if (hmsk & 0x80000000) 5447c478bd9Sstevel@tonic-gate break; 5457c478bd9Sstevel@tonic-gate hmsk <<= 1; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate if (hmsk != 0) { 5487c478bd9Sstevel@tonic-gate hmsk <<= 1; 5497c478bd9Sstevel@tonic-gate goto maskloop; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate } 5527663b816Sml return ipe; 5537663b816Sml } 5547663b816Sml 5557663b816Sml 5567663b816Sml #ifdef USE_INET6 5577663b816Sml /* Locks: ip_poolrw */ 5587663b816Sml static iphtent_t *fr_iphmfind6(iph, addr) 5597663b816Sml iphtable_t *iph; 5607663b816Sml struct in6_addr *addr; 5617663b816Sml { 5627663b816Sml u_32_t hmsk[4], msk[4], ips[4], *and; 5637663b816Sml iphtent_t *ipe; 5647663b816Sml u_int hv; 5657663b816Sml 5667663b816Sml hmsk[0] = iph->iph_masks[0]; 5677663b816Sml hmsk[1] = iph->iph_masks[1]; 5687663b816Sml hmsk[2] = iph->iph_masks[2]; 5697663b816Sml hmsk[3] = iph->iph_masks[3]; 5707663b816Sml 5717663b816Sml msk[0] = 0xffffffff; 5727663b816Sml msk[1] = 0xffffffff; 5737663b816Sml msk[2] = 0xffffffff; 5747663b816Sml msk[3] = 0xffffffff; 5757663b816Sml maskloop: 5767663b816Sml and = (u_32_t *)addr->s6_addr; 5777663b816Sml ips[0] = *and & msk[0]; 5787663b816Sml ips[1] = *(and + 1) & msk[1]; 5797663b816Sml ips[2] = *(and + 2) & msk[2]; 5807663b816Sml ips[3] = *(and + 3) & msk[3]; 5817663b816Sml 5827663b816Sml hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk), 5837663b816Sml iph->iph_size); 5847663b816Sml for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 5857663b816Sml if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) || 5867663b816Sml bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16)) 5877663b816Sml continue; 5887663b816Sml break; 5897663b816Sml } 5907663b816Sml 5917663b816Sml if ((ipe == NULL) && ((hmsk[0] != 0) || 5927663b816Sml (hmsk[1] != 0) || 5937663b816Sml (hmsk[2] != 0) || 5947663b816Sml (hmsk[3] != 0) )) { 5957663b816Sml while ((hmsk[0] != 0) && (hmsk[1] != 0) && 5967663b816Sml (hmsk[2] != 0) && (hmsk[3] != 0)) { 5977663b816Sml left_shift_ipv6((char *)msk); 5987663b816Sml if (hmsk[0] & 0x80000000) 5997663b816Sml break; 6007663b816Sml left_shift_ipv6((char *)hmsk); 6017663b816Sml } 6027663b816Sml if ((hmsk[0] != 0) && (hmsk[1] != 0) && 6037663b816Sml (hmsk[2] != 0) && (hmsk[3] != 0)) { 6047663b816Sml left_shift_ipv6((char *)hmsk); 6057663b816Sml goto maskloop; 6067663b816Sml } 6077663b816Sml } 6087c478bd9Sstevel@tonic-gate return ipe; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117663b816Sml 6127663b816Sml /* 6137663b816Sml * sum4: ipv6 add -> 4 bytes values 6147663b816Sml */ 6157663b816Sml static uint32_t sum4(add) 6167663b816Sml uint32_t *add; 6177663b816Sml { 6187663b816Sml return (*add + *(add + 1) + *(add + 2) + *(add + 3)); 6197663b816Sml } 6207663b816Sml 6217663b816Sml /* 6227663b816Sml * left shift on 128 bits 6237663b816Sml */ 6247663b816Sml static void left_shift_ipv6(data) 6257663b816Sml char *data; 6267663b816Sml { 6277663b816Sml u_32_t *sd; 6287663b816Sml 6297663b816Sml sd = (u_32_t *)data; 6307663b816Sml sd[0] <<= 1; 6317663b816Sml if (sd[1] >= 0x80000000) 6327663b816Sml sd[0] += 1; 6337663b816Sml 6347663b816Sml sd[1] <<= 1; 6357663b816Sml if (sd[2] >= 0x80000000) 6367663b816Sml sd[1] += 1; 6377663b816Sml 6387663b816Sml sd[2] <<= 1; 6397663b816Sml if (sd[3] >= 0x80000000) 6407663b816Sml sd[2] += 1; 6417663b816Sml 6427663b816Sml sd[3] <<= 1; 6437663b816Sml } 6447663b816Sml #endif 645f4b3ec61Sdh 646f4b3ec61Sdh int fr_htable_getnext(token, ilp, ifs) 647f4b3ec61Sdh ipftoken_t *token; 648f4b3ec61Sdh ipflookupiter_t *ilp; 649f4b3ec61Sdh ipf_stack_t *ifs; 650f4b3ec61Sdh { 651f4b3ec61Sdh iphtent_t *node, zn, *nextnode; 652f4b3ec61Sdh iphtable_t *iph, zp, *nextiph; 653f4b3ec61Sdh int err; 654f4b3ec61Sdh 655f4b3ec61Sdh err = 0; 656f4b3ec61Sdh iph = NULL; 657f4b3ec61Sdh node = NULL; 658f4b3ec61Sdh nextiph = NULL; 659f4b3ec61Sdh nextnode = NULL; 660f4b3ec61Sdh 661f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 662f4b3ec61Sdh 663786c7074Sjojemann /* 664786c7074Sjojemann * Get "previous" entry from the token and find the next entry. 665786c7074Sjojemann * 666786c7074Sjojemann * If we found an entry, add a reference to it and update the token. 667786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 668786c7074Sjojemann */ 669f4b3ec61Sdh switch (ilp->ili_otype) 670f4b3ec61Sdh { 671f4b3ec61Sdh case IPFLOOKUPITER_LIST : 672f4b3ec61Sdh iph = token->ipt_data; 673f4b3ec61Sdh if (iph == NULL) { 674f4b3ec61Sdh nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit]; 675f4b3ec61Sdh } else { 676f4b3ec61Sdh nextiph = iph->iph_next; 677f4b3ec61Sdh } 678f4b3ec61Sdh if (nextiph != NULL) { 679786c7074Sjojemann ATOMIC_INC(nextiph->iph_ref); 680786c7074Sjojemann token->ipt_data = nextiph; 681f4b3ec61Sdh } else { 682f4b3ec61Sdh bzero((char *)&zp, sizeof(zp)); 683f4b3ec61Sdh nextiph = &zp; 684786c7074Sjojemann token->ipt_data = NULL; 685f4b3ec61Sdh } 686f4b3ec61Sdh break; 687f4b3ec61Sdh 688f4b3ec61Sdh case IPFLOOKUPITER_NODE : 689f4b3ec61Sdh node = token->ipt_data; 690f4b3ec61Sdh if (node == NULL) { 691f4b3ec61Sdh iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs); 692f4b3ec61Sdh if (iph == NULL) 693f4b3ec61Sdh err = ESRCH; 694f4b3ec61Sdh else { 695f4b3ec61Sdh nextnode = iph->iph_list; 696f4b3ec61Sdh } 697f4b3ec61Sdh } else { 698f4b3ec61Sdh nextnode = node->ipe_snext; 699f4b3ec61Sdh } 700f4b3ec61Sdh if (nextnode != NULL) { 701786c7074Sjojemann ATOMIC_INC(nextnode->ipe_ref); 702786c7074Sjojemann token->ipt_data = nextnode; 703f4b3ec61Sdh } else { 704f4b3ec61Sdh bzero((char *)&zn, sizeof(zn)); 705f4b3ec61Sdh nextnode = &zn; 706786c7074Sjojemann token->ipt_data = NULL; 707f4b3ec61Sdh } 708f4b3ec61Sdh break; 709786c7074Sjojemann 710f4b3ec61Sdh default : 711f4b3ec61Sdh err = EINVAL; 712f4b3ec61Sdh break; 713f4b3ec61Sdh } 714f4b3ec61Sdh 715786c7074Sjojemann /* 716786c7074Sjojemann * Now that we have ref, it's save to give up lock. 717786c7074Sjojemann */ 718f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 719f4b3ec61Sdh if (err != 0) 720f4b3ec61Sdh return err; 721f4b3ec61Sdh 722786c7074Sjojemann /* 723786c7074Sjojemann * Copy out data and clean up references and token as needed. 724786c7074Sjojemann */ 725f4b3ec61Sdh switch (ilp->ili_otype) 726f4b3ec61Sdh { 727f4b3ec61Sdh case IPFLOOKUPITER_LIST : 728f4b3ec61Sdh err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 729f4b3ec61Sdh if (err != 0) 730f4b3ec61Sdh err = EFAULT; 731786c7074Sjojemann if (token->ipt_data == NULL) { 732786c7074Sjojemann ipf_freetoken(token, ifs); 733786c7074Sjojemann } else { 734786c7074Sjojemann if (iph != NULL) { 735786c7074Sjojemann WRITE_ENTER(&ifs->ifs_ip_poolrw); 736786c7074Sjojemann fr_derefhtable(iph, ifs); 737786c7074Sjojemann RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 738786c7074Sjojemann } 739786c7074Sjojemann if (nextiph->iph_next == NULL) 740786c7074Sjojemann ipf_freetoken(token, ifs); 741786c7074Sjojemann } 742f4b3ec61Sdh break; 743f4b3ec61Sdh 744f4b3ec61Sdh case IPFLOOKUPITER_NODE : 745f4b3ec61Sdh err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 746f4b3ec61Sdh if (err != 0) 747f4b3ec61Sdh err = EFAULT; 748786c7074Sjojemann if (token->ipt_data == NULL) { 749786c7074Sjojemann ipf_freetoken(token, ifs); 750786c7074Sjojemann } else { 751786c7074Sjojemann if (node != NULL) { 752786c7074Sjojemann WRITE_ENTER(&ifs->ifs_ip_poolrw); 753786c7074Sjojemann fr_derefhtent(node); 754786c7074Sjojemann RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 755786c7074Sjojemann } 756786c7074Sjojemann if (nextnode->ipe_snext == NULL) 757786c7074Sjojemann ipf_freetoken(token, ifs); 758786c7074Sjojemann } 759f4b3ec61Sdh break; 760f4b3ec61Sdh } 761f4b3ec61Sdh 762f4b3ec61Sdh return err; 763f4b3ec61Sdh } 764f4b3ec61Sdh 765f4b3ec61Sdh 766f4b3ec61Sdh void fr_htable_iterderef(otype, unit, data, ifs) 767f4b3ec61Sdh u_int otype; 768f4b3ec61Sdh int unit; 769f4b3ec61Sdh void *data; 770f4b3ec61Sdh ipf_stack_t *ifs; 771f4b3ec61Sdh { 772f4b3ec61Sdh 773f4b3ec61Sdh if (data == NULL) 774f4b3ec61Sdh return; 775f4b3ec61Sdh 776f4b3ec61Sdh if (unit < 0 || unit > IPL_LOGMAX) 777f4b3ec61Sdh return; 778f4b3ec61Sdh 779f4b3ec61Sdh switch (otype) 780f4b3ec61Sdh { 781f4b3ec61Sdh case IPFLOOKUPITER_LIST : 782f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 783f4b3ec61Sdh fr_derefhtable((iphtable_t *)data, ifs); 784f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 785f4b3ec61Sdh break; 786f4b3ec61Sdh 787f4b3ec61Sdh case IPFLOOKUPITER_NODE : 788f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ip_poolrw); 789f4b3ec61Sdh fr_derefhtent((iphtent_t *)data); 790f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 791f4b3ec61Sdh break; 792f4b3ec61Sdh default : 793f4b3ec61Sdh break; 794f4b3ec61Sdh } 795f4b3ec61Sdh } 7967c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOOKUP */ 797