1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if defined(KERNEL) || defined(_KERNEL) 13 # undef KERNEL 14 # undef _KERNEL 15 # define KERNEL 1 16 # define _KERNEL 1 17 #endif 18 #include <sys/param.h> 19 #include <sys/types.h> 20 #include <sys/errno.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #if !defined(_KERNEL) 24 # include <stdlib.h> 25 # include <string.h> 26 # define _KERNEL 27 # ifdef __OpenBSD__ 28 struct file; 29 # endif 30 # include <sys/uio.h> 31 # undef _KERNEL 32 #endif 33 #include <sys/socket.h> 34 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 35 # include <sys/malloc.h> 36 #endif 37 #if defined(__FreeBSD__) 38 # include <sys/cdefs.h> 39 # include <sys/proc.h> 40 #endif 41 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) 42 # include <sys/mbuf.h> 43 #endif 44 #if defined(_KERNEL) 45 # include <sys/systm.h> 46 #else 47 # include <stdio.h> 48 #endif 49 #include <netinet/in.h> 50 #include <net/if.h> 51 52 #if SOLARIS2 >= 10 53 #include "ip_compat.h" 54 #include "ip_fil.h" 55 #include "ip_lookup.h" 56 #include "ip_htable.h" 57 #else 58 #include "netinet/ip_compat.h" 59 #include "netinet/ip_fil.h" 60 #include "netinet/ip_lookup.h" 61 #include "netinet/ip_htable.h" 62 #endif 63 64 #if !defined(lint) 65 static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.24 2003/05/12 13:49:17 darrenr Exp $"; 66 #endif 67 68 #ifdef IPFILTER_LOOKUP 69 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); 70 71 iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 72 73 74 void fr_htable_unload() 75 { 76 iplookupflush_t fop; 77 iphtable_t *iph; 78 int unit; 79 80 for (unit = 0; unit < IPL_LOGMAX; unit++) { 81 fop.iplf_unit = unit; 82 while ((iph = ipf_htables[unit]) != NULL) { 83 (void)strncpy(fop.iplf_name, iph->iph_name, 84 sizeof(fop.iplf_name)); 85 (void)fr_flushhtable(&fop); 86 } 87 } 88 } 89 90 91 /* 92 * Create a new hash table using the template passed. 93 */ 94 int fr_newhtable(op) 95 iplookupop_t *op; 96 { 97 iphtable_t *iph, *oiph; 98 char name[FR_GROUPLEN]; 99 int err, i, unit; 100 101 KMALLOC(iph, iphtable_t *); 102 if (iph == NULL) 103 return ENOMEM; 104 105 err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); 106 if (err != 0) { 107 KFREE(iph); 108 return EFAULT; 109 } 110 111 unit = op->iplo_unit; 112 if (iph->iph_unit != unit) { 113 KFREE(iph); 114 return EINVAL; 115 } 116 117 if ((op->iplo_arg & IPHASH_ANON) == 0) { 118 if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) { 119 KFREE(iph); 120 return EEXIST; 121 } 122 } else { 123 i = IPHASH_ANON; 124 do { 125 i++; 126 (void)sprintf(name, "%u", i); 127 for (oiph = ipf_htables[unit]; oiph != NULL; 128 oiph = oiph->iph_next) 129 if (strncmp(oiph->iph_name, name, 130 sizeof(oiph->iph_name)) == 0) 131 break; 132 } while (oiph != NULL); 133 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 134 err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); 135 if (err != 0) { 136 KFREE(iph); 137 return EFAULT; 138 } 139 iph->iph_type |= IPHASH_ANON; 140 } 141 142 KMALLOCS(iph->iph_table, iphtent_t **, 143 iph->iph_size * sizeof(*iph->iph_table)); 144 if (iph->iph_table == NULL) { 145 KFREE(iph); 146 return ENOMEM; 147 } 148 149 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 150 iph->iph_masks = 0; 151 152 iph->iph_next = ipf_htables[unit]; 153 iph->iph_pnext = &ipf_htables[unit]; 154 if (ipf_htables[unit] != NULL) 155 ipf_htables[unit]->iph_pnext = &iph->iph_next; 156 ipf_htables[unit] = iph; 157 return 0; 158 } 159 160 161 /* 162 */ 163 int fr_removehtable(op) 164 iplookupop_t *op; 165 { 166 iphtable_t *iph; 167 168 169 iph = fr_findhtable(op->iplo_unit, op->iplo_name); 170 if (iph == NULL) 171 return ESRCH; 172 173 if (iph->iph_unit != op->iplo_unit) { 174 return EINVAL; 175 } 176 177 if (iph->iph_ref != 0) { 178 return EBUSY; 179 } 180 181 fr_delhtable(iph); 182 183 return 0; 184 } 185 186 187 void fr_delhtable(iph) 188 iphtable_t *iph; 189 { 190 191 *iph->iph_pnext = iph->iph_next; 192 if (iph->iph_next != NULL) 193 iph->iph_next->iph_pnext = iph->iph_pnext; 194 195 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 196 KFREE(iph); 197 } 198 199 200 void fr_derefhtable(iph) 201 iphtable_t *iph; 202 { 203 iph->iph_ref--; 204 if (iph->iph_ref == 0) 205 fr_delhtable(iph); 206 } 207 208 209 iphtable_t *fr_findhtable(unit, name) 210 int unit; 211 char *name; 212 { 213 iphtable_t *iph; 214 215 for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next) 216 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) 217 break; 218 return iph; 219 } 220 221 222 size_t fr_flushhtable(op) 223 iplookupflush_t *op; 224 { 225 iphtable_t *iph; 226 size_t i, freed; 227 iphtent_t *ipe; 228 229 iph = fr_findhtable(op->iplf_unit, op->iplf_name); 230 if (iph == NULL) { 231 return 0; 232 } 233 234 freed = 0; 235 *iph->iph_pnext = iph->iph_next; 236 if (iph->iph_next != NULL) 237 iph->iph_next->iph_pnext = iph->iph_pnext; 238 239 for (i = 0; i < iph->iph_size; i++) 240 while ((ipe = iph->iph_table[i]) != NULL) { 241 *ipe->ipe_pnext = ipe->ipe_next; 242 if (ipe->ipe_next != NULL) 243 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 244 245 switch (iph->iph_type & ~IPHASH_ANON) 246 { 247 case IPHASH_GROUPMAP : 248 if (ipe->ipe_ptr != NULL) 249 fr_delgroup(ipe->ipe_group, 250 IPL_LOGIPF, fr_active); 251 break; 252 } 253 /* ipe_ref */ 254 KFREE(ipe); 255 freed++; 256 } 257 258 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 259 KFREE(iph); 260 261 return freed; 262 } 263 264 265 /* 266 * Add an entry to a hash table. 267 */ 268 int fr_addhtent(iph, ipeo) 269 iphtable_t *iph; 270 iphtent_t *ipeo; 271 { 272 iphtent_t *ipe; 273 u_int hv; 274 int bits; 275 276 KMALLOC(ipe, iphtent_t *); 277 if (ipe == NULL) 278 return -1; 279 280 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 281 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; 282 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); 283 bits = count4bits(ipe->ipe_mask.in4_addr); 284 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); 285 286 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, 287 iph->iph_size); 288 ipe->ipe_ref = 0; 289 ipe->ipe_next = iph->iph_table[hv]; 290 ipe->ipe_pnext = iph->iph_table + hv; 291 292 if (iph->iph_table[hv] != NULL) 293 iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; 294 iph->iph_table[hv] = ipe; 295 if ((bits >= 0) && (bits != 32)) 296 iph->iph_masks |= 1 << bits; 297 298 switch (iph->iph_type & ~IPHASH_ANON) 299 { 300 case IPHASH_GROUPMAP : 301 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, 302 iph->iph_flags, IPL_LOGIPF, 303 fr_active); 304 break; 305 306 default : 307 ipe->ipe_ptr = NULL; 308 ipe->ipe_value = 0; 309 break; 310 } 311 312 return 0; 313 } 314 315 316 /* 317 * Delete an entry from a hash table. 318 */ 319 int fr_delhtent(iph, ipe) 320 iphtable_t *iph; 321 iphtent_t *ipe; 322 { 323 324 if (ipe->ipe_ref != 0) 325 return EBUSY; 326 327 328 *ipe->ipe_pnext = ipe->ipe_next; 329 if (ipe->ipe_next != NULL) 330 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 331 332 switch (iph->iph_type & ~IPHASH_ANON) 333 { 334 case IPHASH_GROUPMAP : 335 if (ipe->ipe_group != NULL) 336 fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active); 337 break; 338 339 default : 340 ipe->ipe_ptr = NULL; 341 ipe->ipe_value = 0; 342 break; 343 } 344 345 KFREE(ipe); 346 347 return 0; 348 } 349 350 351 void *fr_iphmfindgroup(tptr, aptr) 352 void *tptr, *aptr; 353 { 354 struct in_addr *addr; 355 iphtable_t *iph; 356 iphtent_t *ipe; 357 void *rval; 358 359 READ_ENTER(&ip_poolrw); 360 iph = tptr; 361 addr = aptr; 362 363 ipe = fr_iphmfind(iph, addr); 364 if (ipe != NULL) 365 rval = ipe->ipe_ptr; 366 else 367 rval = NULL; 368 RWLOCK_EXIT(&ip_poolrw); 369 return rval; 370 } 371 372 373 int fr_iphmfindip(tptr, version, aptr) 374 void *tptr, *aptr; 375 int version; 376 { 377 struct in_addr *addr; 378 iphtable_t *iph; 379 iphtent_t *ipe; 380 int rval; 381 382 if (version != 4) 383 return 1; 384 385 if (tptr == NULL || aptr == NULL) 386 return 1; 387 388 iph = tptr; 389 addr = aptr; 390 391 READ_ENTER(&ip_poolrw); 392 ipe = fr_iphmfind(iph, addr); 393 if (ipe != NULL) 394 rval = 0; 395 else 396 rval = 1; 397 RWLOCK_EXIT(&ip_poolrw); 398 return rval; 399 } 400 401 402 /* Locks: ip_poolrw */ 403 static iphtent_t *fr_iphmfind(iph, addr) 404 iphtable_t *iph; 405 struct in_addr *addr; 406 { 407 u_32_t hmsk, msk, ips; 408 iphtent_t *ipe; 409 u_int hv; 410 411 hmsk = iph->iph_masks; 412 msk = 0xffffffff; 413 maskloop: 414 ips = ntohl(addr->s_addr) & msk; 415 hv = IPE_HASH_FN(ips, msk, iph->iph_size); 416 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 417 if (ipe->ipe_mask.in4_addr != msk || 418 ipe->ipe_addr.in4_addr != ips) { 419 continue; 420 } 421 break; 422 } 423 424 if ((ipe == NULL) && (hmsk != 0)) { 425 while (hmsk != 0) { 426 msk <<= 1; 427 if (hmsk & 0x80000000) 428 break; 429 hmsk <<= 1; 430 } 431 if (hmsk != 0) { 432 hmsk <<= 1; 433 goto maskloop; 434 } 435 } 436 return ipe; 437 } 438 439 #endif /* IPFILTER_LOOKUP */ 440