1ab25eeb5Syz155240 /* 2ab25eeb5Syz155240 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3ab25eeb5Syz155240 * 4ab25eeb5Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz155240 * 6*de22af4eSJohn Ojemann * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 7ab25eeb5Syz155240 */ 8ab25eeb5Syz155240 9ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL) 10ab25eeb5Syz155240 # undef KERNEL 11ab25eeb5Syz155240 # undef _KERNEL 12ab25eeb5Syz155240 # define KERNEL 1 13ab25eeb5Syz155240 # define _KERNEL 1 14ab25eeb5Syz155240 #endif 15ab25eeb5Syz155240 #include <sys/param.h> 16ab25eeb5Syz155240 #include <sys/types.h> 17ab25eeb5Syz155240 #include <sys/errno.h> 18ab25eeb5Syz155240 #include <sys/time.h> 19ab25eeb5Syz155240 #include <sys/file.h> 20ab25eeb5Syz155240 #if !defined(_KERNEL) 21ab25eeb5Syz155240 # include <stdlib.h> 22ab25eeb5Syz155240 # include <string.h> 23ab25eeb5Syz155240 # define _KERNEL 24ab25eeb5Syz155240 # ifdef __OpenBSD__ 25ab25eeb5Syz155240 struct file; 26ab25eeb5Syz155240 # endif 27ab25eeb5Syz155240 # include <sys/uio.h> 28ab25eeb5Syz155240 # undef _KERNEL 29ab25eeb5Syz155240 #endif 30ab25eeb5Syz155240 #include <sys/socket.h> 31ab25eeb5Syz155240 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 32ab25eeb5Syz155240 # include <sys/malloc.h> 33ab25eeb5Syz155240 #endif 34ab25eeb5Syz155240 #if defined(__FreeBSD__) 35ab25eeb5Syz155240 # include <sys/cdefs.h> 36ab25eeb5Syz155240 # include <sys/proc.h> 37ab25eeb5Syz155240 #endif 38ab25eeb5Syz155240 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ 39ab25eeb5Syz155240 !defined(linux) 40ab25eeb5Syz155240 # include <sys/mbuf.h> 41ab25eeb5Syz155240 #endif 42ab25eeb5Syz155240 #if defined(_KERNEL) 43ab25eeb5Syz155240 # include <sys/systm.h> 44ab25eeb5Syz155240 #else 45ab25eeb5Syz155240 # include <stdio.h> 46ab25eeb5Syz155240 #endif 47ab25eeb5Syz155240 #include <netinet/in.h> 48ab25eeb5Syz155240 #include <net/if.h> 49ab25eeb5Syz155240 50ab25eeb5Syz155240 #include "netinet/ip_compat.h" 51ab25eeb5Syz155240 #include "netinet/ip_fil.h" 52ab25eeb5Syz155240 #include "netinet/ip_lookup.h" 53ab25eeb5Syz155240 #include "netinet/ip_htable.h" 54f4b3ec61Sdh155122 #include "netinet/ipf_stack.h" 55ab25eeb5Syz155240 /* END OF INCLUDES */ 56ab25eeb5Syz155240 57ab25eeb5Syz155240 #if !defined(lint) 58ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $"; 59ab25eeb5Syz155240 #endif 60ab25eeb5Syz155240 61ab25eeb5Syz155240 #ifdef IPFILTER_LOOKUP 62ab25eeb5Syz155240 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); 63ab25eeb5Syz155240 #ifdef USE_INET6 64ab25eeb5Syz155240 static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *)); 65ab25eeb5Syz155240 static uint32_t sum4(uint32_t *); 66ab25eeb5Syz155240 static void left_shift_ipv6 __P((char *)); 67ab25eeb5Syz155240 #endif 68ab25eeb5Syz155240 69f4b3ec61Sdh155122 void fr_htable_unload(ifs) 70f4b3ec61Sdh155122 ipf_stack_t *ifs; 71ab25eeb5Syz155240 { 72ab25eeb5Syz155240 iplookupflush_t fop; 73ab25eeb5Syz155240 74ab25eeb5Syz155240 fop.iplf_unit = IPL_LOGALL; 75f4b3ec61Sdh155122 (void)fr_flushhtable(&fop, ifs); 76ab25eeb5Syz155240 } 77ab25eeb5Syz155240 78ab25eeb5Syz155240 79f4b3ec61Sdh155122 int fr_gethtablestat(op, ifs) 80ab25eeb5Syz155240 iplookupop_t *op; 81f4b3ec61Sdh155122 ipf_stack_t *ifs; 82ab25eeb5Syz155240 { 83ab25eeb5Syz155240 iphtstat_t stats; 84ab25eeb5Syz155240 85ab25eeb5Syz155240 if (op->iplo_size != sizeof(stats)) 86ab25eeb5Syz155240 return EINVAL; 87ab25eeb5Syz155240 88f4b3ec61Sdh155122 stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit]; 89f4b3ec61Sdh155122 stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit]; 90f4b3ec61Sdh155122 stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit]; 91f4b3ec61Sdh155122 stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit]; 92ab25eeb5Syz155240 93ab25eeb5Syz155240 return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 94ab25eeb5Syz155240 95ab25eeb5Syz155240 } 96ab25eeb5Syz155240 97ab25eeb5Syz155240 98ab25eeb5Syz155240 /* 99ab25eeb5Syz155240 * Create a new hash table using the template passed. 100ab25eeb5Syz155240 */ 101f4b3ec61Sdh155122 int fr_newhtable(op, ifs) 102ab25eeb5Syz155240 iplookupop_t *op; 103f4b3ec61Sdh155122 ipf_stack_t *ifs; 104ab25eeb5Syz155240 { 105ab25eeb5Syz155240 iphtable_t *iph, *oiph; 106ab25eeb5Syz155240 char name[FR_GROUPLEN]; 107ab25eeb5Syz155240 int err, i, unit; 108ab25eeb5Syz155240 109ab25eeb5Syz155240 KMALLOC(iph, iphtable_t *); 110ab25eeb5Syz155240 if (iph == NULL) { 111f4b3ec61Sdh155122 ifs->ifs_ipht_nomem[op->iplo_unit]++; 112ab25eeb5Syz155240 return ENOMEM; 113ab25eeb5Syz155240 } 114ab25eeb5Syz155240 115ab25eeb5Syz155240 err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); 116ab25eeb5Syz155240 if (err != 0) { 117ab25eeb5Syz155240 KFREE(iph); 118ab25eeb5Syz155240 return EFAULT; 119ab25eeb5Syz155240 } 120ab25eeb5Syz155240 121ab25eeb5Syz155240 unit = op->iplo_unit; 122ab25eeb5Syz155240 if (iph->iph_unit != unit) { 123ab25eeb5Syz155240 KFREE(iph); 124ab25eeb5Syz155240 return EINVAL; 125ab25eeb5Syz155240 } 126ab25eeb5Syz155240 127ab25eeb5Syz155240 if ((op->iplo_arg & IPHASH_ANON) == 0) { 128f4b3ec61Sdh155122 if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) { 129ab25eeb5Syz155240 KFREE(iph); 130ab25eeb5Syz155240 return EEXIST; 131ab25eeb5Syz155240 } 132ab25eeb5Syz155240 } else { 133ab25eeb5Syz155240 i = IPHASH_ANON; 134ab25eeb5Syz155240 do { 135ab25eeb5Syz155240 i++; 136ab25eeb5Syz155240 #if defined(SNPRINTF) && defined(_KERNEL) 137ab25eeb5Syz155240 (void)SNPRINTF(name, sizeof(name), "%u", i); 138ab25eeb5Syz155240 #else 139ab25eeb5Syz155240 (void)sprintf(name, "%u", i); 140ab25eeb5Syz155240 #endif 141f4b3ec61Sdh155122 for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL; 142ab25eeb5Syz155240 oiph = oiph->iph_next) 143ab25eeb5Syz155240 if (strncmp(oiph->iph_name, name, 144ab25eeb5Syz155240 sizeof(oiph->iph_name)) == 0) 145ab25eeb5Syz155240 break; 146ab25eeb5Syz155240 } while (oiph != NULL); 147ab25eeb5Syz155240 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 148ab25eeb5Syz155240 err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); 149ab25eeb5Syz155240 if (err != 0) { 150ab25eeb5Syz155240 KFREE(iph); 151ab25eeb5Syz155240 return EFAULT; 152ab25eeb5Syz155240 } 153ab25eeb5Syz155240 iph->iph_type |= IPHASH_ANON; 154ab25eeb5Syz155240 } 155ab25eeb5Syz155240 156ab25eeb5Syz155240 KMALLOCS(iph->iph_table, iphtent_t **, 157ab25eeb5Syz155240 iph->iph_size * sizeof(*iph->iph_table)); 158ab25eeb5Syz155240 if (iph->iph_table == NULL) { 159ab25eeb5Syz155240 KFREE(iph); 160f4b3ec61Sdh155122 ifs->ifs_ipht_nomem[unit]++; 161ab25eeb5Syz155240 return ENOMEM; 162ab25eeb5Syz155240 } 163ab25eeb5Syz155240 164ab25eeb5Syz155240 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 165ab25eeb5Syz155240 iph->iph_masks[0] = 0; 166ab25eeb5Syz155240 iph->iph_masks[1] = 0; 167ab25eeb5Syz155240 iph->iph_masks[2] = 0; 168ab25eeb5Syz155240 iph->iph_masks[3] = 0; 169f4b3ec61Sdh155122 iph->iph_list = NULL; 170ab25eeb5Syz155240 171f4b3ec61Sdh155122 iph->iph_ref = 1; 172f4b3ec61Sdh155122 iph->iph_next = ifs->ifs_ipf_htables[unit]; 173f4b3ec61Sdh155122 iph->iph_pnext = &ifs->ifs_ipf_htables[unit]; 174f4b3ec61Sdh155122 if (ifs->ifs_ipf_htables[unit] != NULL) 175f4b3ec61Sdh155122 ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next; 176f4b3ec61Sdh155122 ifs->ifs_ipf_htables[unit] = iph; 177ab25eeb5Syz155240 178f4b3ec61Sdh155122 ifs->ifs_ipf_nhtables[unit]++; 179ab25eeb5Syz155240 180ab25eeb5Syz155240 return 0; 181ab25eeb5Syz155240 } 182ab25eeb5Syz155240 183ab25eeb5Syz155240 184ab25eeb5Syz155240 /* 185ab25eeb5Syz155240 */ 186f4b3ec61Sdh155122 int fr_removehtable(op, ifs) 187ab25eeb5Syz155240 iplookupop_t *op; 188f4b3ec61Sdh155122 ipf_stack_t *ifs; 189ab25eeb5Syz155240 { 190ab25eeb5Syz155240 iphtable_t *iph; 191ab25eeb5Syz155240 192ab25eeb5Syz155240 193f4b3ec61Sdh155122 iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs); 194ab25eeb5Syz155240 if (iph == NULL) 195ab25eeb5Syz155240 return ESRCH; 196ab25eeb5Syz155240 197ab25eeb5Syz155240 if (iph->iph_unit != op->iplo_unit) { 198ab25eeb5Syz155240 return EINVAL; 199ab25eeb5Syz155240 } 200ab25eeb5Syz155240 201f4b3ec61Sdh155122 if (iph->iph_ref != 1) { 202ab25eeb5Syz155240 return EBUSY; 203ab25eeb5Syz155240 } 204ab25eeb5Syz155240 205f4b3ec61Sdh155122 fr_delhtable(iph, ifs); 206ab25eeb5Syz155240 207ab25eeb5Syz155240 return 0; 208ab25eeb5Syz155240 } 209ab25eeb5Syz155240 210ab25eeb5Syz155240 211f4b3ec61Sdh155122 void fr_delhtable(iph, ifs) 212ab25eeb5Syz155240 iphtable_t *iph; 213f4b3ec61Sdh155122 ipf_stack_t *ifs; 214ab25eeb5Syz155240 { 215ab25eeb5Syz155240 iphtent_t *ipe; 216ab25eeb5Syz155240 int i; 217ab25eeb5Syz155240 218ab25eeb5Syz155240 for (i = 0; i < iph->iph_size; i++) 219ab25eeb5Syz155240 while ((ipe = iph->iph_table[i]) != NULL) 220f4b3ec61Sdh155122 if (fr_delhtent(iph, ipe, ifs) != 0) 221ab25eeb5Syz155240 return; 222ab25eeb5Syz155240 223ab25eeb5Syz155240 *iph->iph_pnext = iph->iph_next; 224ab25eeb5Syz155240 if (iph->iph_next != NULL) 225ab25eeb5Syz155240 iph->iph_next->iph_pnext = iph->iph_pnext; 226ab25eeb5Syz155240 227f4b3ec61Sdh155122 ifs->ifs_ipf_nhtables[iph->iph_unit]--; 228ab25eeb5Syz155240 229f4b3ec61Sdh155122 if (iph->iph_ref == 1) { 230ab25eeb5Syz155240 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 231ab25eeb5Syz155240 KFREE(iph); 232ab25eeb5Syz155240 } 233ab25eeb5Syz155240 } 234ab25eeb5Syz155240 235ab25eeb5Syz155240 236f4b3ec61Sdh155122 void fr_derefhtable(iph, ifs) 237ab25eeb5Syz155240 iphtable_t *iph; 238f4b3ec61Sdh155122 ipf_stack_t *ifs; 239ab25eeb5Syz155240 { 240ab25eeb5Syz155240 iph->iph_ref--; 241ab25eeb5Syz155240 if (iph->iph_ref == 0) 242f4b3ec61Sdh155122 fr_delhtable(iph, ifs); 243ab25eeb5Syz155240 } 244ab25eeb5Syz155240 245ab25eeb5Syz155240 246f4b3ec61Sdh155122 void fr_derefhtent(ipe) 247f4b3ec61Sdh155122 iphtent_t *ipe; 248f4b3ec61Sdh155122 { 249f4b3ec61Sdh155122 ipe->ipe_ref--; 250f4b3ec61Sdh155122 if (ipe->ipe_ref == 0) { 251f4b3ec61Sdh155122 KFREE(ipe); 252f4b3ec61Sdh155122 } 253f4b3ec61Sdh155122 } 254f4b3ec61Sdh155122 255f4b3ec61Sdh155122 256f4b3ec61Sdh155122 iphtable_t *fr_findhtable(unit, name, ifs) 257ab25eeb5Syz155240 int unit; 258ab25eeb5Syz155240 char *name; 259f4b3ec61Sdh155122 ipf_stack_t *ifs; 260ab25eeb5Syz155240 { 261ab25eeb5Syz155240 iphtable_t *iph; 262ab25eeb5Syz155240 263f4b3ec61Sdh155122 for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next) 264ab25eeb5Syz155240 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) 265ab25eeb5Syz155240 break; 266ab25eeb5Syz155240 return iph; 267ab25eeb5Syz155240 } 268ab25eeb5Syz155240 269ab25eeb5Syz155240 270f4b3ec61Sdh155122 size_t fr_flushhtable(op, ifs) 271ab25eeb5Syz155240 iplookupflush_t *op; 272f4b3ec61Sdh155122 ipf_stack_t *ifs; 273ab25eeb5Syz155240 { 274ab25eeb5Syz155240 iphtable_t *iph; 275ab25eeb5Syz155240 size_t freed; 276ab25eeb5Syz155240 int i; 277ab25eeb5Syz155240 278ab25eeb5Syz155240 freed = 0; 279ab25eeb5Syz155240 280ab25eeb5Syz155240 for (i = 0; i <= IPL_LOGMAX; i++) { 281ab25eeb5Syz155240 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 282f4b3ec61Sdh155122 while ((iph = ifs->ifs_ipf_htables[i]) != NULL) { 283f4b3ec61Sdh155122 fr_delhtable(iph, ifs); 284ab25eeb5Syz155240 freed++; 285ab25eeb5Syz155240 } 286ab25eeb5Syz155240 } 287ab25eeb5Syz155240 } 288ab25eeb5Syz155240 289ab25eeb5Syz155240 return freed; 290ab25eeb5Syz155240 } 291ab25eeb5Syz155240 292ab25eeb5Syz155240 293ab25eeb5Syz155240 /* 294ab25eeb5Syz155240 * Add an entry to a hash table. 295ab25eeb5Syz155240 */ 296f4b3ec61Sdh155122 int fr_addhtent(iph, ipeo, ifs) 297ab25eeb5Syz155240 iphtable_t *iph; 298ab25eeb5Syz155240 iphtent_t *ipeo; 299f4b3ec61Sdh155122 ipf_stack_t *ifs; 300ab25eeb5Syz155240 { 301ab25eeb5Syz155240 iphtent_t *ipe; 302ab25eeb5Syz155240 u_int hv; 303ab25eeb5Syz155240 int bits; 304ab25eeb5Syz155240 305ab25eeb5Syz155240 KMALLOC(ipe, iphtent_t *); 306ab25eeb5Syz155240 if (ipe == NULL) 307ab25eeb5Syz155240 return -1; 308ab25eeb5Syz155240 309ab25eeb5Syz155240 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 310ab25eeb5Syz155240 #ifdef USE_INET6 311ab25eeb5Syz155240 if (ipe->ipe_family == AF_INET6) { 312ab25eeb5Syz155240 bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8); 313ab25eeb5Syz155240 hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8), 314ab25eeb5Syz155240 sum4((uint32_t *)ipe->ipe_mask.in6_addr8), 315ab25eeb5Syz155240 iph->iph_size); 316ab25eeb5Syz155240 } else 317ab25eeb5Syz155240 #endif 318ab25eeb5Syz155240 if (ipe->ipe_family == AF_INET) 319ab25eeb5Syz155240 { 320ab25eeb5Syz155240 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; 321ab25eeb5Syz155240 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); 322ab25eeb5Syz155240 bits = count4bits(ipe->ipe_mask.in4_addr); 323ab25eeb5Syz155240 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); 324ab25eeb5Syz155240 325ab25eeb5Syz155240 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, 326ab25eeb5Syz155240 iph->iph_size); 327ab25eeb5Syz155240 } else 328ab25eeb5Syz155240 return -1; 329ab25eeb5Syz155240 330f4b3ec61Sdh155122 ipe->ipe_ref = 1; 331ab25eeb5Syz155240 ipe->ipe_next = iph->iph_table[hv]; 332ab25eeb5Syz155240 ipe->ipe_pnext = iph->iph_table + hv; 333ab25eeb5Syz155240 334ab25eeb5Syz155240 if (iph->iph_table[hv] != NULL) 335ab25eeb5Syz155240 iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; 336ab25eeb5Syz155240 iph->iph_table[hv] = ipe; 337f4b3ec61Sdh155122 338f4b3ec61Sdh155122 ipe->ipe_snext = iph->iph_list; 339f4b3ec61Sdh155122 ipe->ipe_psnext = &iph->iph_list; 340f4b3ec61Sdh155122 if (ipe->ipe_next != NULL) 341f4b3ec61Sdh155122 ipe->ipe_next->ipe_psnext = &ipe->ipe_snext; 342f4b3ec61Sdh155122 iph->iph_list = ipe; 343f4b3ec61Sdh155122 344ab25eeb5Syz155240 #ifdef USE_INET6 345ab25eeb5Syz155240 if (ipe->ipe_family == AF_INET6) { 346ab25eeb5Syz155240 if ((bits >= 0) && (bits != 128)) 347ab25eeb5Syz155240 if (bits >= 96) 348ab25eeb5Syz155240 iph->iph_masks[0] |= 1 << (bits - 96); 349ab25eeb5Syz155240 else if (bits >= 64) 350ab25eeb5Syz155240 iph->iph_masks[1] |= 1 << (bits - 64); 351ab25eeb5Syz155240 else if (bits >= 32) 352ab25eeb5Syz155240 iph->iph_masks[2] |= 1 << (bits - 32); 353ab25eeb5Syz155240 else 354ab25eeb5Syz155240 iph->iph_masks[3] |= 1 << bits; 355ab25eeb5Syz155240 356ab25eeb5Syz155240 } else 357ab25eeb5Syz155240 #endif 358ab25eeb5Syz155240 { 359ab25eeb5Syz155240 if ((bits >= 0) && (bits != 32)) 360ab25eeb5Syz155240 iph->iph_masks[3] |= 1 << bits; 361ab25eeb5Syz155240 } 362ab25eeb5Syz155240 363ab25eeb5Syz155240 switch (iph->iph_type & ~IPHASH_ANON) 364ab25eeb5Syz155240 { 365ab25eeb5Syz155240 case IPHASH_GROUPMAP : 366ab25eeb5Syz155240 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, 367ab25eeb5Syz155240 iph->iph_flags, IPL_LOGIPF, 368f4b3ec61Sdh155122 ifs->ifs_fr_active, ifs); 369ab25eeb5Syz155240 break; 370ab25eeb5Syz155240 371ab25eeb5Syz155240 default : 372ab25eeb5Syz155240 ipe->ipe_ptr = NULL; 373ab25eeb5Syz155240 ipe->ipe_value = 0; 374ab25eeb5Syz155240 break; 375ab25eeb5Syz155240 } 376ab25eeb5Syz155240 377f4b3ec61Sdh155122 ifs->ifs_ipf_nhtnodes[iph->iph_unit]++; 378ab25eeb5Syz155240 379ab25eeb5Syz155240 return 0; 380ab25eeb5Syz155240 } 381ab25eeb5Syz155240 382ab25eeb5Syz155240 383ab25eeb5Syz155240 /* 384ab25eeb5Syz155240 * Delete an entry from a hash table. 385ab25eeb5Syz155240 */ 386f4b3ec61Sdh155122 int fr_delhtent(iph, ipe, ifs) 387ab25eeb5Syz155240 iphtable_t *iph; 388ab25eeb5Syz155240 iphtent_t *ipe; 389f4b3ec61Sdh155122 ipf_stack_t *ifs; 390ab25eeb5Syz155240 { 391f4b3ec61Sdh155122 if (ipe->ipe_ref != 1) 392ab25eeb5Syz155240 return EBUSY; 393ab25eeb5Syz155240 394ab25eeb5Syz155240 395ab25eeb5Syz155240 *ipe->ipe_pnext = ipe->ipe_next; 396ab25eeb5Syz155240 if (ipe->ipe_next != NULL) 397ab25eeb5Syz155240 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 398ab25eeb5Syz155240 399ab25eeb5Syz155240 switch (iph->iph_type & ~IPHASH_ANON) 400ab25eeb5Syz155240 { 401ab25eeb5Syz155240 case IPHASH_GROUPMAP : 402ab25eeb5Syz155240 if (ipe->ipe_group != NULL) 403f4b3ec61Sdh155122 fr_delgroup(ipe->ipe_group, IPL_LOGIPF, 404f4b3ec61Sdh155122 ifs->ifs_fr_active, ifs); 405ab25eeb5Syz155240 break; 406ab25eeb5Syz155240 407ab25eeb5Syz155240 default : 408ab25eeb5Syz155240 ipe->ipe_ptr = NULL; 409ab25eeb5Syz155240 ipe->ipe_value = 0; 410ab25eeb5Syz155240 break; 411ab25eeb5Syz155240 } 412ab25eeb5Syz155240 413ab25eeb5Syz155240 KFREE(ipe); 414ab25eeb5Syz155240 415f4b3ec61Sdh155122 ifs->ifs_ipf_nhtnodes[iph->iph_unit]--; 416ab25eeb5Syz155240 417ab25eeb5Syz155240 return 0; 418ab25eeb5Syz155240 } 419ab25eeb5Syz155240 420ab25eeb5Syz155240 421f4b3ec61Sdh155122 void *fr_iphmfindgroup(tptr, version, aptr, ifs) 422ab25eeb5Syz155240 void *tptr; 423ab25eeb5Syz155240 int version; 424ab25eeb5Syz155240 void *aptr; 425f4b3ec61Sdh155122 ipf_stack_t *ifs; 426ab25eeb5Syz155240 { 427ab25eeb5Syz155240 i6addr_t *addr; 428ab25eeb5Syz155240 iphtable_t *iph; 429ab25eeb5Syz155240 iphtent_t *ipe; 430ab25eeb5Syz155240 void *rval; 431ab25eeb5Syz155240 432ab25eeb5Syz155240 if ((version != 4) 433ab25eeb5Syz155240 #ifdef USE_INET6 434ab25eeb5Syz155240 && (version != 6) 435ab25eeb5Syz155240 #endif 436ab25eeb5Syz155240 ) 437ab25eeb5Syz155240 return NULL; 438ab25eeb5Syz155240 439f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ip_poolrw); 440ab25eeb5Syz155240 iph = tptr; 441ab25eeb5Syz155240 addr = aptr; 442ab25eeb5Syz155240 443ab25eeb5Syz155240 #ifdef USE_INET6 444ab25eeb5Syz155240 if (version == 6) 445ab25eeb5Syz155240 ipe = fr_iphmfind6(iph, &addr->in6); 446ab25eeb5Syz155240 else 447ab25eeb5Syz155240 #endif 448ab25eeb5Syz155240 if (version == 4) 449ab25eeb5Syz155240 ipe = fr_iphmfind(iph, &addr->in4); 450ab25eeb5Syz155240 else 451ab25eeb5Syz155240 ipe = NULL; 452ab25eeb5Syz155240 if (ipe != NULL) 453ab25eeb5Syz155240 rval = ipe->ipe_ptr; 454ab25eeb5Syz155240 else 455ab25eeb5Syz155240 rval = NULL; 456f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 457ab25eeb5Syz155240 return rval; 458ab25eeb5Syz155240 } 459ab25eeb5Syz155240 460ab25eeb5Syz155240 461ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 462ab25eeb5Syz155240 /* Function: fr_iphmfindip */ 463ab25eeb5Syz155240 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 464ab25eeb5Syz155240 /* Parameters: tptr(I) - pointer to the pool to search */ 465ab25eeb5Syz155240 /* version(I) - IP protocol version (4 or 6) */ 466ab25eeb5Syz155240 /* aptr(I) - pointer to address information */ 467*de22af4eSJohn Ojemann /* fin - pointer to packet information */ 468*de22af4eSJohn Ojemann /* ifs - ipf stack instance */ 469ab25eeb5Syz155240 /* */ 470ab25eeb5Syz155240 /* Search the hash table for a given address and return a search result. */ 471ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 472*de22af4eSJohn Ojemann int fr_iphmfindip(tptr, version, aptr, fin, ifs) 473ab25eeb5Syz155240 void *tptr, *aptr; 474ab25eeb5Syz155240 int version; 475*de22af4eSJohn Ojemann fr_info_t *fin; 476f4b3ec61Sdh155122 ipf_stack_t *ifs; 477ab25eeb5Syz155240 { 478ab25eeb5Syz155240 i6addr_t *addr; 479ab25eeb5Syz155240 iphtable_t *iph; 480ab25eeb5Syz155240 iphtent_t *ipe; 481ab25eeb5Syz155240 int rval; 482ab25eeb5Syz155240 483ab25eeb5Syz155240 if ((version != 4) 484ab25eeb5Syz155240 #ifdef USE_INET6 485ab25eeb5Syz155240 && (version != 6) 486ab25eeb5Syz155240 #endif 487ab25eeb5Syz155240 ) 488ab25eeb5Syz155240 return -1; 489ab25eeb5Syz155240 490ab25eeb5Syz155240 if (tptr == NULL || aptr == NULL) 491ab25eeb5Syz155240 return -1; 492ab25eeb5Syz155240 493ab25eeb5Syz155240 iph = tptr; 494ab25eeb5Syz155240 addr = aptr; 495ab25eeb5Syz155240 496f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ip_poolrw); 497ab25eeb5Syz155240 #ifdef USE_INET6 498ab25eeb5Syz155240 if (version == 6) 499ab25eeb5Syz155240 ipe = fr_iphmfind6(iph, &addr->in6); 500ab25eeb5Syz155240 else 501ab25eeb5Syz155240 #endif 502ab25eeb5Syz155240 if (version == 4) 503ab25eeb5Syz155240 ipe = fr_iphmfind(iph, &addr->in4); 504ab25eeb5Syz155240 else 505ab25eeb5Syz155240 ipe = NULL; 506*de22af4eSJohn Ojemann if (ipe != NULL) { 507*de22af4eSJohn Ojemann ipe->ipe_hits++; 508*de22af4eSJohn Ojemann ipe->ipe_bytes += fin->fin_plen; 509ab25eeb5Syz155240 rval = 0; 510*de22af4eSJohn Ojemann } else { 511ab25eeb5Syz155240 rval = 1; 512*de22af4eSJohn Ojemann } 513f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 514ab25eeb5Syz155240 return rval; 515ab25eeb5Syz155240 } 516ab25eeb5Syz155240 517ab25eeb5Syz155240 518ab25eeb5Syz155240 /* Locks: ip_poolrw */ 519ab25eeb5Syz155240 static iphtent_t *fr_iphmfind(iph, addr) 520ab25eeb5Syz155240 iphtable_t *iph; 521ab25eeb5Syz155240 struct in_addr *addr; 522ab25eeb5Syz155240 { 523ab25eeb5Syz155240 u_32_t hmsk, msk, ips; 524ab25eeb5Syz155240 iphtent_t *ipe; 525ab25eeb5Syz155240 u_int hv; 526ab25eeb5Syz155240 527ab25eeb5Syz155240 hmsk = iph->iph_masks[3]; 528ab25eeb5Syz155240 msk = 0xffffffff; 529ab25eeb5Syz155240 maskloop: 530ab25eeb5Syz155240 ips = ntohl(addr->s_addr) & msk; 531ab25eeb5Syz155240 hv = IPE_HASH_FN(ips, msk, iph->iph_size); 532ab25eeb5Syz155240 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 533ab25eeb5Syz155240 if (ipe->ipe_mask.in4_addr != msk || 534ab25eeb5Syz155240 ipe->ipe_addr.in4_addr != ips) { 535ab25eeb5Syz155240 continue; 536ab25eeb5Syz155240 } 537ab25eeb5Syz155240 break; 538ab25eeb5Syz155240 } 539ab25eeb5Syz155240 540ab25eeb5Syz155240 if ((ipe == NULL) && (hmsk != 0)) { 541ab25eeb5Syz155240 while (hmsk != 0) { 542ab25eeb5Syz155240 msk <<= 1; 543ab25eeb5Syz155240 if (hmsk & 0x80000000) 544ab25eeb5Syz155240 break; 545ab25eeb5Syz155240 hmsk <<= 1; 546ab25eeb5Syz155240 } 547ab25eeb5Syz155240 if (hmsk != 0) { 548ab25eeb5Syz155240 hmsk <<= 1; 549ab25eeb5Syz155240 goto maskloop; 550ab25eeb5Syz155240 } 551ab25eeb5Syz155240 } 552ab25eeb5Syz155240 return ipe; 553ab25eeb5Syz155240 } 554ab25eeb5Syz155240 555ab25eeb5Syz155240 556ab25eeb5Syz155240 #ifdef USE_INET6 557ab25eeb5Syz155240 /* Locks: ip_poolrw */ 558ab25eeb5Syz155240 static iphtent_t *fr_iphmfind6(iph, addr) 559ab25eeb5Syz155240 iphtable_t *iph; 560ab25eeb5Syz155240 struct in6_addr *addr; 561ab25eeb5Syz155240 { 562ab25eeb5Syz155240 u_32_t hmsk[4], msk[4], ips[4], *and; 563ab25eeb5Syz155240 iphtent_t *ipe; 564ab25eeb5Syz155240 u_int hv; 565ab25eeb5Syz155240 566ab25eeb5Syz155240 hmsk[0] = iph->iph_masks[0]; 567ab25eeb5Syz155240 hmsk[1] = iph->iph_masks[1]; 568ab25eeb5Syz155240 hmsk[2] = iph->iph_masks[2]; 569ab25eeb5Syz155240 hmsk[3] = iph->iph_masks[3]; 570ab25eeb5Syz155240 571ab25eeb5Syz155240 msk[0] = 0xffffffff; 572ab25eeb5Syz155240 msk[1] = 0xffffffff; 573ab25eeb5Syz155240 msk[2] = 0xffffffff; 574ab25eeb5Syz155240 msk[3] = 0xffffffff; 575ab25eeb5Syz155240 maskloop: 576ab25eeb5Syz155240 and = (u_32_t *)addr->s6_addr; 577ab25eeb5Syz155240 ips[0] = *and & msk[0]; 578ab25eeb5Syz155240 ips[1] = *(and + 1) & msk[1]; 579ab25eeb5Syz155240 ips[2] = *(and + 2) & msk[2]; 580ab25eeb5Syz155240 ips[3] = *(and + 3) & msk[3]; 581ab25eeb5Syz155240 582ab25eeb5Syz155240 hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk), 583ab25eeb5Syz155240 iph->iph_size); 584ab25eeb5Syz155240 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 585ab25eeb5Syz155240 if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) || 586ab25eeb5Syz155240 bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16)) 587ab25eeb5Syz155240 continue; 588ab25eeb5Syz155240 break; 589ab25eeb5Syz155240 } 590ab25eeb5Syz155240 591ab25eeb5Syz155240 if ((ipe == NULL) && ((hmsk[0] != 0) || 592ab25eeb5Syz155240 (hmsk[1] != 0) || 593ab25eeb5Syz155240 (hmsk[2] != 0) || 594ab25eeb5Syz155240 (hmsk[3] != 0) )) { 595ab25eeb5Syz155240 while ((hmsk[0] != 0) && (hmsk[1] != 0) && 596ab25eeb5Syz155240 (hmsk[2] != 0) && (hmsk[3] != 0)) { 597ab25eeb5Syz155240 left_shift_ipv6((char *)msk); 598ab25eeb5Syz155240 if (hmsk[0] & 0x80000000) 599ab25eeb5Syz155240 break; 600ab25eeb5Syz155240 left_shift_ipv6((char *)hmsk); 601ab25eeb5Syz155240 } 602ab25eeb5Syz155240 if ((hmsk[0] != 0) && (hmsk[1] != 0) && 603ab25eeb5Syz155240 (hmsk[2] != 0) && (hmsk[3] != 0)) { 604ab25eeb5Syz155240 left_shift_ipv6((char *)hmsk); 605ab25eeb5Syz155240 goto maskloop; 606ab25eeb5Syz155240 } 607ab25eeb5Syz155240 } 608ab25eeb5Syz155240 return ipe; 609ab25eeb5Syz155240 } 610ab25eeb5Syz155240 611ab25eeb5Syz155240 612ab25eeb5Syz155240 /* 613ab25eeb5Syz155240 * sum4: ipv6 add -> 4 bytes values 614ab25eeb5Syz155240 */ 615ab25eeb5Syz155240 static uint32_t sum4(add) 616ab25eeb5Syz155240 uint32_t *add; 617ab25eeb5Syz155240 { 618ab25eeb5Syz155240 return (*add + *(add + 1) + *(add + 2) + *(add + 3)); 619ab25eeb5Syz155240 } 620ab25eeb5Syz155240 621ab25eeb5Syz155240 /* 622ab25eeb5Syz155240 * left shift on 128 bits 623ab25eeb5Syz155240 */ 624ab25eeb5Syz155240 static void left_shift_ipv6(data) 625ab25eeb5Syz155240 char *data; 626ab25eeb5Syz155240 { 627ab25eeb5Syz155240 u_32_t *sd; 628ab25eeb5Syz155240 629ab25eeb5Syz155240 sd = (u_32_t *)data; 630ab25eeb5Syz155240 sd[0] <<= 1; 631ab25eeb5Syz155240 if (sd[1] >= 0x80000000) 632ab25eeb5Syz155240 sd[0] += 1; 633ab25eeb5Syz155240 634ab25eeb5Syz155240 sd[1] <<= 1; 635ab25eeb5Syz155240 if (sd[2] >= 0x80000000) 636ab25eeb5Syz155240 sd[1] += 1; 637ab25eeb5Syz155240 638ab25eeb5Syz155240 sd[2] <<= 1; 639ab25eeb5Syz155240 if (sd[3] >= 0x80000000) 640ab25eeb5Syz155240 sd[2] += 1; 641ab25eeb5Syz155240 642ab25eeb5Syz155240 sd[3] <<= 1; 643ab25eeb5Syz155240 } 644ab25eeb5Syz155240 #endif 645f4b3ec61Sdh155122 646f4b3ec61Sdh155122 int fr_htable_getnext(token, ilp, ifs) 647f4b3ec61Sdh155122 ipftoken_t *token; 648f4b3ec61Sdh155122 ipflookupiter_t *ilp; 649f4b3ec61Sdh155122 ipf_stack_t *ifs; 650f4b3ec61Sdh155122 { 651f4b3ec61Sdh155122 iphtent_t *node, zn, *nextnode; 652f4b3ec61Sdh155122 iphtable_t *iph, zp, *nextiph; 653f4b3ec61Sdh155122 int err; 654f4b3ec61Sdh155122 655f4b3ec61Sdh155122 err = 0; 656f4b3ec61Sdh155122 iph = NULL; 657f4b3ec61Sdh155122 node = NULL; 658f4b3ec61Sdh155122 nextiph = NULL; 659f4b3ec61Sdh155122 nextnode = NULL; 660f4b3ec61Sdh155122 661f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ip_poolrw); 662f4b3ec61Sdh155122 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 */ 669f4b3ec61Sdh155122 switch (ilp->ili_otype) 670f4b3ec61Sdh155122 { 671f4b3ec61Sdh155122 case IPFLOOKUPITER_LIST : 672f4b3ec61Sdh155122 iph = token->ipt_data; 673f4b3ec61Sdh155122 if (iph == NULL) { 674f4b3ec61Sdh155122 nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit]; 675f4b3ec61Sdh155122 } else { 676f4b3ec61Sdh155122 nextiph = iph->iph_next; 677f4b3ec61Sdh155122 } 678f4b3ec61Sdh155122 if (nextiph != NULL) { 679f4b3ec61Sdh155122 ATOMIC_INC(nextiph->iph_ref); 680786c7074Sjojemann token->ipt_data = nextiph; 681f4b3ec61Sdh155122 } else { 682f4b3ec61Sdh155122 bzero((char *)&zp, sizeof(zp)); 683f4b3ec61Sdh155122 nextiph = &zp; 684786c7074Sjojemann token->ipt_data = NULL; 685f4b3ec61Sdh155122 } 686f4b3ec61Sdh155122 break; 687f4b3ec61Sdh155122 688f4b3ec61Sdh155122 case IPFLOOKUPITER_NODE : 689f4b3ec61Sdh155122 node = token->ipt_data; 690f4b3ec61Sdh155122 if (node == NULL) { 691f4b3ec61Sdh155122 iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs); 692f4b3ec61Sdh155122 if (iph == NULL) 693f4b3ec61Sdh155122 err = ESRCH; 694f4b3ec61Sdh155122 else { 695f4b3ec61Sdh155122 nextnode = iph->iph_list; 696f4b3ec61Sdh155122 } 697f4b3ec61Sdh155122 } else { 698f4b3ec61Sdh155122 nextnode = node->ipe_snext; 699f4b3ec61Sdh155122 } 700f4b3ec61Sdh155122 if (nextnode != NULL) { 701f4b3ec61Sdh155122 ATOMIC_INC(nextnode->ipe_ref); 702786c7074Sjojemann token->ipt_data = nextnode; 703f4b3ec61Sdh155122 } else { 704f4b3ec61Sdh155122 bzero((char *)&zn, sizeof(zn)); 705f4b3ec61Sdh155122 nextnode = &zn; 706786c7074Sjojemann token->ipt_data = NULL; 707f4b3ec61Sdh155122 } 708f4b3ec61Sdh155122 break; 709786c7074Sjojemann 710f4b3ec61Sdh155122 default : 711f4b3ec61Sdh155122 err = EINVAL; 712f4b3ec61Sdh155122 break; 713f4b3ec61Sdh155122 } 714f4b3ec61Sdh155122 715786c7074Sjojemann /* 716786c7074Sjojemann * Now that we have ref, it's save to give up lock. 717786c7074Sjojemann */ 718f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 719f4b3ec61Sdh155122 if (err != 0) 720f4b3ec61Sdh155122 return err; 721f4b3ec61Sdh155122 722786c7074Sjojemann /* 723786c7074Sjojemann * Copy out data and clean up references and token as needed. 724786c7074Sjojemann */ 725f4b3ec61Sdh155122 switch (ilp->ili_otype) 726f4b3ec61Sdh155122 { 727f4b3ec61Sdh155122 case IPFLOOKUPITER_LIST : 728786c7074Sjojemann err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 729786c7074Sjojemann if (err != 0) 730786c7074Sjojemann err = EFAULT; 731786c7074Sjojemann if (token->ipt_data == NULL) { 732786c7074Sjojemann ipf_freetoken(token, ifs); 733786c7074Sjojemann } else { 734f4b3ec61Sdh155122 if (iph != NULL) { 735f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ip_poolrw); 736f4b3ec61Sdh155122 fr_derefhtable(iph, ifs); 737f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 738f4b3ec61Sdh155122 } 739786c7074Sjojemann if (nextiph->iph_next == NULL) 740786c7074Sjojemann ipf_freetoken(token, ifs); 741786c7074Sjojemann } 742f4b3ec61Sdh155122 break; 743f4b3ec61Sdh155122 744f4b3ec61Sdh155122 case IPFLOOKUPITER_NODE : 745786c7074Sjojemann err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 746786c7074Sjojemann if (err != 0) 747786c7074Sjojemann err = EFAULT; 748786c7074Sjojemann if (token->ipt_data == NULL) { 749786c7074Sjojemann ipf_freetoken(token, ifs); 750786c7074Sjojemann } else { 751f4b3ec61Sdh155122 if (node != NULL) { 752f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ip_poolrw); 753f4b3ec61Sdh155122 fr_derefhtent(node); 754f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 755f4b3ec61Sdh155122 } 756786c7074Sjojemann if (nextnode->ipe_snext == NULL) 757786c7074Sjojemann ipf_freetoken(token, ifs); 758786c7074Sjojemann } 759f4b3ec61Sdh155122 break; 760f4b3ec61Sdh155122 } 761f4b3ec61Sdh155122 762f4b3ec61Sdh155122 return err; 763f4b3ec61Sdh155122 } 764f4b3ec61Sdh155122 765f4b3ec61Sdh155122 766f4b3ec61Sdh155122 void fr_htable_iterderef(otype, unit, data, ifs) 767f4b3ec61Sdh155122 u_int otype; 768f4b3ec61Sdh155122 int unit; 769f4b3ec61Sdh155122 void *data; 770f4b3ec61Sdh155122 ipf_stack_t *ifs; 771f4b3ec61Sdh155122 { 772f4b3ec61Sdh155122 773f4b3ec61Sdh155122 if (data == NULL) 774f4b3ec61Sdh155122 return; 775f4b3ec61Sdh155122 776f4b3ec61Sdh155122 if (unit < 0 || unit > IPL_LOGMAX) 777f4b3ec61Sdh155122 return; 778f4b3ec61Sdh155122 779f4b3ec61Sdh155122 switch (otype) 780f4b3ec61Sdh155122 { 781f4b3ec61Sdh155122 case IPFLOOKUPITER_LIST : 782f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ip_poolrw); 783f4b3ec61Sdh155122 fr_derefhtable((iphtable_t *)data, ifs); 784f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 785f4b3ec61Sdh155122 break; 786f4b3ec61Sdh155122 787f4b3ec61Sdh155122 case IPFLOOKUPITER_NODE : 788f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ip_poolrw); 789f4b3ec61Sdh155122 fr_derefhtent((iphtent_t *)data); 790f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 791f4b3ec61Sdh155122 break; 792f4b3ec61Sdh155122 default : 793f4b3ec61Sdh155122 break; 794f4b3ec61Sdh155122 } 795f4b3ec61Sdh155122 } 796ab25eeb5Syz155240 #endif /* IPFILTER_LOOKUP */ 797