1
2 /*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7 #if defined(KERNEL) || defined(_KERNEL)
8 # undef KERNEL
9 # undef _KERNEL
10 # define KERNEL 1
11 # define _KERNEL 1
12 #endif
13 #include <sys/param.h>
14 #include <sys/types.h>
15 #include <sys/errno.h>
16 #include <sys/time.h>
17 #include <sys/file.h>
18 #if !defined(_KERNEL)
19 # include <stdlib.h>
20 # include <string.h>
21 # define _KERNEL
22 # include <sys/uio.h>
23 # undef _KERNEL
24 #endif
25 #include <sys/socket.h>
26 #if defined(__FreeBSD__)
27 # include <sys/malloc.h>
28 #endif
29 #if defined(__FreeBSD__)
30 # include <sys/cdefs.h>
31 # include <sys/proc.h>
32 #endif
33 #if !defined(__SVR4)
34 # include <sys/mbuf.h>
35 #endif
36 #if defined(_KERNEL)
37 # include <sys/systm.h>
38 #else
39 # include "ipf.h"
40 #endif
41 #include <netinet/in.h>
42 #include <net/if.h>
43
44 #include "netinet/ip_compat.h"
45 #include "netinet/ip_fil.h"
46 #include "netinet/ip_lookup.h"
47 #include "netinet/ip_htable.h"
48 /* END OF INCLUDES */
49
50
51 # ifdef USE_INET6
52 static iphtent_t *ipf_iphmfind6(iphtable_t *, i6addr_t *);
53 # endif
54 static iphtent_t *ipf_iphmfind(iphtable_t *, struct in_addr *);
55 static int ipf_iphmfindip(ipf_main_softc_t *, void *, int, void *, u_int);
56 static int ipf_htable_clear(ipf_main_softc_t *, void *, iphtable_t *);
57 static int ipf_htable_create(ipf_main_softc_t *, void *, iplookupop_t *);
58 static int ipf_htable_deref(ipf_main_softc_t *, void *, void *);
59 static int ipf_htable_destroy(ipf_main_softc_t *, void *, int, char *);
60 static void *ipf_htable_exists(void *, int, char *);
61 static size_t ipf_htable_flush(ipf_main_softc_t *, void *,
62 iplookupflush_t *);
63 static void ipf_htable_free(void *, iphtable_t *);
64 static int ipf_htable_iter_deref(ipf_main_softc_t *, void *, int,
65 int, void *);
66 static int ipf_htable_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
67 ipflookupiter_t *);
68 static int ipf_htable_node_add(ipf_main_softc_t *, void *,
69 iplookupop_t *, int);
70 static int ipf_htable_node_del(ipf_main_softc_t *, void *,
71 iplookupop_t *, int);
72 static int ipf_htable_remove(ipf_main_softc_t *, void *, iphtable_t *);
73 static void *ipf_htable_soft_create(ipf_main_softc_t *);
74 static void ipf_htable_soft_destroy(ipf_main_softc_t *, void *);
75 static int ipf_htable_soft_init(ipf_main_softc_t *, void *);
76 static void ipf_htable_soft_fini(ipf_main_softc_t *, void *);
77 static int ipf_htable_stats_get(ipf_main_softc_t *, void *,
78 iplookupop_t *);
79 static int ipf_htable_table_add(ipf_main_softc_t *, void *,
80 iplookupop_t *);
81 static int ipf_htable_table_del(ipf_main_softc_t *, void *,
82 iplookupop_t *);
83 static int ipf_htent_deref(void *, iphtent_t *);
84 static iphtent_t *ipf_htent_find(iphtable_t *, iphtent_t *);
85 static int ipf_htent_insert(ipf_main_softc_t *, void *, iphtable_t *,
86 iphtent_t *);
87 static int ipf_htent_remove(ipf_main_softc_t *, void *, iphtable_t *,
88 iphtent_t *);
89 static void *ipf_htable_select_add_ref(void *, int, char *);
90 static void ipf_htable_expire(ipf_main_softc_t *, void *);
91
92
93 typedef struct ipf_htable_softc_s {
94 u_long ipht_nomem[LOOKUP_POOL_SZ];
95 u_long ipf_nhtables[LOOKUP_POOL_SZ];
96 u_long ipf_nhtnodes[LOOKUP_POOL_SZ];
97 iphtable_t *ipf_htables[LOOKUP_POOL_SZ];
98 iphtent_t *ipf_node_explist;
99 ipftuneable_t *ipf_htable_tune;
100 u_int ipf_htable_size_max;
101 } ipf_htable_softc_t;
102
103 ipf_lookup_t ipf_htable_backend = {
104 IPLT_HASH,
105 ipf_htable_soft_create,
106 ipf_htable_soft_destroy,
107 ipf_htable_soft_init,
108 ipf_htable_soft_fini,
109 ipf_iphmfindip,
110 ipf_htable_flush,
111 ipf_htable_iter_deref,
112 ipf_htable_iter_next,
113 ipf_htable_node_add,
114 ipf_htable_node_del,
115 ipf_htable_stats_get,
116 ipf_htable_table_add,
117 ipf_htable_table_del,
118 ipf_htable_deref,
119 ipf_htable_exists,
120 ipf_htable_select_add_ref,
121 NULL,
122 ipf_htable_expire,
123 NULL
124 };
125
126
127 static ipftuneable_t ipf_htable_tuneables[] = {
128 { { (void *)offsetof(ipf_htable_softc_t, ipf_htable_size_max) },
129 "htable_size_max", 1, 0x7fffffff,
130 stsizeof(ipf_htable_softc_t, ipf_htable_size_max),
131 0, NULL, NULL },
132 { { NULL },
133 NULL, 0, 0,
134 0,
135 0, NULL, NULL }
136 };
137
138
139 /* ------------------------------------------------------------------------ */
140 /* Function: ipf_htable_soft_create */
141 /* Returns: void * - NULL = failure, else pointer to local context */
142 /* Parameters: softc(I) - pointer to soft context main structure */
143 /* */
144 /* Initialise the routing table data structures where required. */
145 /* ------------------------------------------------------------------------ */
146 static void *
ipf_htable_soft_create(ipf_main_softc_t * softc)147 ipf_htable_soft_create(ipf_main_softc_t *softc)
148 {
149 ipf_htable_softc_t *softh;
150
151 KMALLOC(softh, ipf_htable_softc_t *);
152 if (softh == NULL) {
153 IPFERROR(30026);
154 return (NULL);
155 }
156
157 bzero((char *)softh, sizeof(*softh));
158
159 softh->ipf_htable_tune = ipf_tune_array_copy(softh,
160 sizeof(ipf_htable_tuneables),
161 ipf_htable_tuneables);
162 if (softh->ipf_htable_tune == NULL) {
163 ipf_htable_soft_destroy(softc, softh);
164 return (NULL);
165 }
166 if (ipf_tune_array_link(softc, softh->ipf_htable_tune) == -1) {
167 ipf_htable_soft_destroy(softc, softh);
168 return (NULL);
169 }
170
171 return (softh);
172 }
173
174
175 /* ------------------------------------------------------------------------ */
176 /* Function: ipf_htable_soft_destroy */
177 /* Returns: Nil */
178 /* Parameters: softc(I) - pointer to soft context main structure */
179 /* arg(I) - pointer to local context to use */
180 /* */
181 /* Clean up the pool by free'ing the radix tree associated with it and free */
182 /* up the pool context too. */
183 /* ------------------------------------------------------------------------ */
184 static void
ipf_htable_soft_destroy(ipf_main_softc_t * softc,void * arg)185 ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg)
186 {
187 ipf_htable_softc_t *softh = arg;
188
189 if (softh->ipf_htable_tune != NULL) {
190 ipf_tune_array_unlink(softc, softh->ipf_htable_tune);
191 KFREES(softh->ipf_htable_tune, sizeof(ipf_htable_tuneables));
192 softh->ipf_htable_tune = NULL;
193 }
194
195 KFREE(softh);
196 }
197
198
199 /* ------------------------------------------------------------------------ */
200 /* Function: ipf_htable_soft_init */
201 /* Returns: int - 0 = success, else error */
202 /* Parameters: softc(I) - pointer to soft context main structure */
203 /* arg(I) - pointer to local context to use */
204 /* */
205 /* Initialise the hash table ready for use. */
206 /* ------------------------------------------------------------------------ */
207 static int
ipf_htable_soft_init(ipf_main_softc_t * softc,void * arg)208 ipf_htable_soft_init(ipf_main_softc_t *softc, void *arg)
209 {
210 ipf_htable_softc_t *softh = arg;
211
212 bzero((char *)softh, sizeof(*softh));
213
214 softh->ipf_htable_size_max = IPHTABLE_MAX_SIZE;
215
216 return (0);
217 }
218
219
220 /* ------------------------------------------------------------------------ */
221 /* Function: ipf_htable_soft_fini */
222 /* Returns: Nil */
223 /* Parameters: softc(I) - pointer to soft context main structure */
224 /* arg(I) - pointer to local context to use */
225 /* Locks: WRITE(ipf_global) */
226 /* */
227 /* Clean up all the pool data structures allocated and call the cleanup */
228 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
229 /* used to delete the pools one by one to ensure they're properly freed up. */
230 /* ------------------------------------------------------------------------ */
231 static void
ipf_htable_soft_fini(ipf_main_softc_t * softc,void * arg)232 ipf_htable_soft_fini(ipf_main_softc_t *softc, void *arg)
233 {
234 iplookupflush_t fop;
235
236 fop.iplf_type = IPLT_HASH;
237 fop.iplf_unit = IPL_LOGALL;
238 fop.iplf_arg = 0;
239 fop.iplf_count = 0;
240 *fop.iplf_name = '\0';
241 ipf_htable_flush(softc, arg, &fop);
242 }
243
244
245 /* ------------------------------------------------------------------------ */
246 /* Function: ipf_htable_stats_get */
247 /* Returns: int - 0 = success, else error */
248 /* Parameters: softc(I) - pointer to soft context main structure */
249 /* arg(I) - pointer to local context to use */
250 /* op(I) - pointer to lookup operation data */
251 /* */
252 /* Copy the relevant statistics out of internal structures and into the */
253 /* structure used to export statistics. */
254 /* ------------------------------------------------------------------------ */
255 static int
ipf_htable_stats_get(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)256 ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
257 {
258 ipf_htable_softc_t *softh = arg;
259 iphtstat_t stats;
260 int err;
261
262 if (op->iplo_size != sizeof(stats)) {
263 IPFERROR(30001);
264 return (EINVAL);
265 }
266
267 bzero(&stats, sizeof(stats));
268
269 stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
270 stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
271 stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
272 stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
273
274 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
275 if (err != 0) {
276 IPFERROR(30013);
277 return (EFAULT);
278 }
279 return (0);
280
281 }
282
283
284 /* ------------------------------------------------------------------------ */
285 /* Function: ipf_htable_create */
286 /* Returns: int - 0 = success, else error */
287 /* Parameters: softc(I) - pointer to soft context main structure */
288 /* arg(I) - pointer to local context to use */
289 /* op(I) - pointer to lookup operation data */
290 /* */
291 /* Create a new hash table using the template passed. */
292 /* ------------------------------------------------------------------------ */
293 static int
ipf_htable_create(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)294 ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
295 {
296 ipf_htable_softc_t *softh = arg;
297 iphtable_t htab, *iph, *oiph;
298 char name[FR_GROUPLEN];
299 int err, i, unit;
300
301 if (op->iplo_size != sizeof(htab)) {
302 IPFERROR(30024);
303 return (EINVAL);
304 }
305 err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
306 if (err != 0) {
307 IPFERROR(30003);
308 return (EFAULT);
309 }
310
311 unit = op->iplo_unit;
312 if (htab.iph_unit != unit) {
313 IPFERROR(30005);
314 return (EINVAL);
315 }
316 if (htab.iph_size < 1) {
317 IPFERROR(30025);
318 return (EINVAL);
319 }
320
321
322 if ((op->iplo_arg & IPHASH_ANON) == 0) {
323 iph = ipf_htable_exists(softh, unit, op->iplo_name);
324 if (iph != NULL) {
325 if ((iph->iph_flags & IPHASH_DELETE) == 0) {
326 IPFERROR(30004);
327 return (EEXIST);
328 }
329 iph->iph_flags &= ~IPHASH_DELETE;
330 iph->iph_ref++;
331 return (0);
332 }
333 }
334
335 KMALLOC(iph, iphtable_t *);
336 if (iph == NULL) {
337 softh->ipht_nomem[op->iplo_unit + 1]++;
338 IPFERROR(30002);
339 return (ENOMEM);
340 }
341 *iph = htab;
342
343 if ((op->iplo_arg & IPHASH_ANON) != 0) {
344 i = IPHASH_ANON;
345 do {
346 i++;
347 (void)snprintf(name, sizeof(name), "%u", i);
348 for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
349 oiph = oiph->iph_next)
350 if (strncmp(oiph->iph_name, name,
351 sizeof(oiph->iph_name)) == 0)
352 break;
353 } while (oiph != NULL);
354
355 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
356 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
357 iph->iph_type |= IPHASH_ANON;
358 } else {
359 (void)strncpy(iph->iph_name, op->iplo_name,
360 sizeof(iph->iph_name));
361 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
362 }
363
364 if ((iph->iph_size == 0) ||
365 (iph->iph_size > softh->ipf_htable_size_max)) {
366 IPFERROR(30027);
367 return (EINVAL);
368 }
369 if (iph->iph_size > ( SIZE_MAX / sizeof(*iph->iph_table))) {
370 IPFERROR(30028);
371 return (EINVAL);
372 }
373 KMALLOCS(iph->iph_table, iphtent_t **,
374 iph->iph_size * sizeof(*iph->iph_table));
375 if (iph->iph_table == NULL) {
376 KFREE(iph);
377 softh->ipht_nomem[unit + 1]++;
378 IPFERROR(30006);
379 return (ENOMEM);
380 }
381
382 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
383 iph->iph_maskset[0] = 0;
384 iph->iph_maskset[1] = 0;
385 iph->iph_maskset[2] = 0;
386 iph->iph_maskset[3] = 0;
387
388 iph->iph_ref = 1;
389 iph->iph_list = NULL;
390 iph->iph_tail = &iph->iph_list;
391 iph->iph_unit = unit;
392 iph->iph_next = softh->ipf_htables[unit + 1];
393 iph->iph_pnext = &softh->ipf_htables[unit + 1];
394 if (softh->ipf_htables[unit + 1] != NULL)
395 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
396 softh->ipf_htables[unit + 1] = iph;
397
398 softh->ipf_nhtables[unit + 1]++;
399
400 return (0);
401 }
402
403
404 /* ------------------------------------------------------------------------ */
405 /* Function: ipf_htable_table_del */
406 /* Returns: int - 0 = success, else error */
407 /* Parameters: softc(I) - pointer to soft context main structure */
408 /* arg(I) - pointer to local context to use */
409 /* op(I) - pointer to lookup operation data */
410 /* */
411 /* ------------------------------------------------------------------------ */
412 static int
ipf_htable_table_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)413 ipf_htable_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
414 {
415 return (ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name));
416 }
417
418
419 /* ------------------------------------------------------------------------ */
420 /* Function: ipf_htable_destroy */
421 /* Returns: int - 0 = success, else error */
422 /* Parameters: softc(I) - pointer to soft context main structure */
423 /* arg(I) - pointer to local context to use */
424 /* op(I) - pointer to lookup operation data */
425 /* */
426 /* Find the hash table that belongs to the relevant part of ipfilter with a */
427 /* matching name and attempt to destroy it. If it is in use, empty it out */
428 /* and mark it for deletion so that when all the references disappear, it */
429 /* can be removed. */
430 /* ------------------------------------------------------------------------ */
431 static int
ipf_htable_destroy(ipf_main_softc_t * softc,void * arg,int unit,char * name)432 ipf_htable_destroy(ipf_main_softc_t *softc, void *arg, int unit, char *name)
433 {
434 iphtable_t *iph;
435
436 iph = ipf_htable_find(arg, unit, name);
437 if (iph == NULL) {
438 IPFERROR(30007);
439 return (ESRCH);
440 }
441
442 if (iph->iph_unit != unit) {
443 IPFERROR(30008);
444 return (EINVAL);
445 }
446
447 if (iph->iph_ref != 0) {
448 ipf_htable_clear(softc, arg, iph);
449 iph->iph_flags |= IPHASH_DELETE;
450 return (0);
451 }
452
453 ipf_htable_remove(softc, arg, iph);
454
455 return (0);
456 }
457
458
459 /* ------------------------------------------------------------------------ */
460 /* Function: ipf_htable_clear */
461 /* Returns: int - 0 = success, else error */
462 /* Parameters: softc(I) - pointer to soft context main structure */
463 /* arg(I) - pointer to local context to use */
464 /* iph(I) - pointer to hash table to destroy */
465 /* */
466 /* Clean out the hash table by walking the list of entries and removing */
467 /* each one, one by one. */
468 /* ------------------------------------------------------------------------ */
469 static int
ipf_htable_clear(ipf_main_softc_t * softc,void * arg,iphtable_t * iph)470 ipf_htable_clear(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
471 {
472 iphtent_t *ipe;
473
474 while ((ipe = iph->iph_list) != NULL)
475 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
476 return (1);
477 return (0);
478 }
479
480
481 /* ------------------------------------------------------------------------ */
482 /* Function: ipf_htable_free */
483 /* Returns: Nil */
484 /* Parameters: arg(I) - pointer to local context to use */
485 /* iph(I) - pointer to hash table to destroy */
486 /* */
487 /* ------------------------------------------------------------------------ */
488 static void
ipf_htable_free(void * arg,iphtable_t * iph)489 ipf_htable_free(void *arg, iphtable_t *iph)
490 {
491 ipf_htable_softc_t *softh = arg;
492
493 if (iph->iph_next != NULL)
494 iph->iph_next->iph_pnext = iph->iph_pnext;
495 if (iph->iph_pnext != NULL)
496 *iph->iph_pnext = iph->iph_next;
497 iph->iph_pnext = NULL;
498 iph->iph_next = NULL;
499
500 softh->ipf_nhtables[iph->iph_unit + 1]--;
501
502 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
503 KFREE(iph);
504 }
505
506
507 /* ------------------------------------------------------------------------ */
508 /* Function: ipf_htable_remove */
509 /* Returns: int - 0 = success, else error */
510 /* Parameters: softc(I) - pointer to soft context main structure */
511 /* arg(I) - pointer to local context to use */
512 /* iph(I) - pointer to hash table to destroy */
513 /* */
514 /* It is necessary to unlink here as well as free (called by deref) so that */
515 /* the while loop in ipf_htable_flush() functions properly. */
516 /* ------------------------------------------------------------------------ */
517 static int
ipf_htable_remove(ipf_main_softc_t * softc,void * arg,iphtable_t * iph)518 ipf_htable_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
519 {
520
521 if (ipf_htable_clear(softc, arg, iph) != 0)
522 return (1);
523
524 if (iph->iph_pnext != NULL)
525 *iph->iph_pnext = iph->iph_next;
526 if (iph->iph_next != NULL)
527 iph->iph_next->iph_pnext = iph->iph_pnext;
528 iph->iph_pnext = NULL;
529 iph->iph_next = NULL;
530
531 return (ipf_htable_deref(softc, arg, iph));
532 }
533
534
535 /* ------------------------------------------------------------------------ */
536 /* Function: ipf_htable_node_del */
537 /* Returns: int - 0 = success, else error */
538 /* Parameters: softc(I) - pointer to soft context main structure */
539 /* arg(I) - pointer to local context to use */
540 /* op(I) - pointer to lookup operation data */
541 /* uid(I) - real uid of process doing operation */
542 /* */
543 /* ------------------------------------------------------------------------ */
544 static int
ipf_htable_node_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)545 ipf_htable_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
546 int uid)
547 {
548 iphtable_t *iph;
549 iphtent_t hte, *ent;
550 int err;
551
552 if (op->iplo_size != sizeof(hte)) {
553 IPFERROR(30014);
554 return (EINVAL);
555 }
556
557 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
558 if (err != 0) {
559 IPFERROR(30015);
560 return (EFAULT);
561 }
562
563 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
564 if (iph == NULL) {
565 IPFERROR(30016);
566 return (ESRCH);
567 }
568
569 ent = ipf_htent_find(iph, &hte);
570 if (ent == NULL) {
571 IPFERROR(30022);
572 return (ESRCH);
573 }
574
575 if ((uid != 0) && (ent->ipe_uid != uid)) {
576 IPFERROR(30023);
577 return (EACCES);
578 }
579
580 err = ipf_htent_remove(softc, arg, iph, ent);
581
582 return (err);
583 }
584
585
586 /* ------------------------------------------------------------------------ */
587 /* Function: ipf_htable_node_del */
588 /* Returns: int - 0 = success, else error */
589 /* Parameters: softc(I) - pointer to soft context main structure */
590 /* arg(I) - pointer to local context to use */
591 /* op(I) - pointer to lookup operation data */
592 /* */
593 /* ------------------------------------------------------------------------ */
594 static int
ipf_htable_table_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)595 ipf_htable_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
596 {
597 int err;
598
599 if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
600 IPFERROR(30017);
601 err = EEXIST;
602 } else {
603 err = ipf_htable_create(softc, arg, op);
604 }
605
606 return (err);
607 }
608
609
610 /* ------------------------------------------------------------------------ */
611 /* Function: ipf_htent_remove */
612 /* Returns: int - 0 = success, else error */
613 /* Parameters: softc(I) - pointer to soft context main structure */
614 /* arg(I) - pointer to local context to use */
615 /* iph(I) - pointer to hash table */
616 /* ipe(I) - pointer to hash table entry to remove */
617 /* */
618 /* Delete an entry from a hash table. */
619 /* ------------------------------------------------------------------------ */
620 static int
ipf_htent_remove(ipf_main_softc_t * softc,void * arg,iphtable_t * iph,iphtent_t * ipe)621 ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
622 iphtent_t *ipe)
623 {
624
625 if (iph->iph_tail == &ipe->ipe_next)
626 iph->iph_tail = ipe->ipe_pnext;
627
628 if (ipe->ipe_hnext != NULL)
629 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
630 if (ipe->ipe_phnext != NULL)
631 *ipe->ipe_phnext = ipe->ipe_hnext;
632 ipe->ipe_phnext = NULL;
633 ipe->ipe_hnext = NULL;
634
635 if (ipe->ipe_dnext != NULL)
636 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
637 if (ipe->ipe_pdnext != NULL)
638 *ipe->ipe_pdnext = ipe->ipe_dnext;
639 ipe->ipe_pdnext = NULL;
640 ipe->ipe_dnext = NULL;
641
642 if (ipe->ipe_next != NULL)
643 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
644 if (ipe->ipe_pnext != NULL)
645 *ipe->ipe_pnext = ipe->ipe_next;
646 ipe->ipe_pnext = NULL;
647 ipe->ipe_next = NULL;
648
649 switch (iph->iph_type & ~IPHASH_ANON)
650 {
651 case IPHASH_GROUPMAP :
652 if (ipe->ipe_ptr != NULL)
653 ipf_group_del(softc, ipe->ipe_ptr, NULL);
654 break;
655
656 default :
657 ipe->ipe_ptr = NULL;
658 ipe->ipe_value = 0;
659 break;
660 }
661
662 return (ipf_htent_deref(arg, ipe));
663 }
664
665
666 /* ------------------------------------------------------------------------ */
667 /* Function: ipf_htable_deref */
668 /* Returns: int - 0 = success, else error */
669 /* Parameters: softc(I) - pointer to soft context main structure */
670 /* arg(I) - pointer to local context to use */
671 /* object(I) - pointer to hash table */
672 /* */
673 /* ------------------------------------------------------------------------ */
674 static int
ipf_htable_deref(ipf_main_softc_t * softc,void * arg,void * object)675 ipf_htable_deref(ipf_main_softc_t *softc, void *arg, void *object)
676 {
677 ipf_htable_softc_t *softh = arg;
678 iphtable_t *iph = object;
679 int refs;
680
681 iph->iph_ref--;
682 refs = iph->iph_ref;
683
684 if (iph->iph_ref == 0) {
685 ipf_htable_free(softh, iph);
686 }
687
688 return (refs);
689 }
690
691
692 /* ------------------------------------------------------------------------ */
693 /* Function: ipf_htent_deref */
694 /* Parameters: arg(I) - pointer to local context to use */
695 /* ipe(I) - */
696 /* */
697 /* ------------------------------------------------------------------------ */
698 static int
ipf_htent_deref(void * arg,iphtent_t * ipe)699 ipf_htent_deref(void *arg, iphtent_t *ipe)
700 {
701 ipf_htable_softc_t *softh = arg;
702
703 ipe->ipe_ref--;
704 if (ipe->ipe_ref == 0) {
705 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
706 KFREE(ipe);
707
708 return (0);
709 }
710
711 return (ipe->ipe_ref);
712 }
713
714
715 /* ------------------------------------------------------------------------ */
716 /* Function: ipf_htable_exists */
717 /* Parameters: arg(I) - pointer to local context to use */
718 /* */
719 /* ------------------------------------------------------------------------ */
720 static void *
ipf_htable_exists(void * arg,int unit,char * name)721 ipf_htable_exists(void *arg, int unit, char *name)
722 {
723 ipf_htable_softc_t *softh = arg;
724 iphtable_t *iph;
725
726 if (unit == IPL_LOGALL) {
727 int i;
728
729 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
730 for (iph = softh->ipf_htables[i]; iph != NULL;
731 iph = iph->iph_next) {
732 if (strncmp(iph->iph_name, name,
733 sizeof(iph->iph_name)) == 0)
734 break;
735 }
736 if (iph != NULL)
737 break;
738 }
739 } else {
740 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
741 iph = iph->iph_next) {
742 if (strncmp(iph->iph_name, name,
743 sizeof(iph->iph_name)) == 0)
744 break;
745 }
746 }
747 return (iph);
748 }
749
750
751 /* ------------------------------------------------------------------------ */
752 /* Function: ipf_htable_select_add_ref */
753 /* Returns: void * - NULL = failure, else pointer to the hash table */
754 /* Parameters: arg(I) - pointer to local context to use */
755 /* unit(I) - ipfilter device to which we are working on */
756 /* name(I) - name of the hash table */
757 /* */
758 /* ------------------------------------------------------------------------ */
759 static void *
ipf_htable_select_add_ref(void * arg,int unit,char * name)760 ipf_htable_select_add_ref(void *arg, int unit, char *name)
761 {
762 iphtable_t *iph;
763
764 iph = ipf_htable_exists(arg, unit, name);
765 if (iph != NULL) {
766 ATOMIC_INC32(iph->iph_ref);
767 }
768 return (iph);
769 }
770
771
772 /* ------------------------------------------------------------------------ */
773 /* Function: ipf_htable_find */
774 /* Returns: void * - NULL = failure, else pointer to the hash table */
775 /* Parameters: arg(I) - pointer to local context to use */
776 /* unit(I) - ipfilter device to which we are working on */
777 /* name(I) - name of the hash table */
778 /* */
779 /* This function is exposed becaues it is used in the group-map feature. */
780 /* ------------------------------------------------------------------------ */
781 iphtable_t *
ipf_htable_find(void * arg,int unit,char * name)782 ipf_htable_find(void *arg, int unit, char *name)
783 {
784 iphtable_t *iph;
785
786 iph = ipf_htable_exists(arg, unit, name);
787 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
788 return (iph);
789
790 return (NULL);
791 }
792
793
794 /* ------------------------------------------------------------------------ */
795 /* Function: ipf_htable_flush */
796 /* Returns: size_t - number of entries flushed */
797 /* Parameters: softc(I) - pointer to soft context main structure */
798 /* arg(I) - pointer to local context to use */
799 /* op(I) - pointer to lookup operation data */
800 /* */
801 /* ------------------------------------------------------------------------ */
802 static size_t
ipf_htable_flush(ipf_main_softc_t * softc,void * arg,iplookupflush_t * op)803 ipf_htable_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *op)
804 {
805 ipf_htable_softc_t *softh = arg;
806 iphtable_t *iph;
807 size_t freed;
808 int i;
809
810 freed = 0;
811
812 for (i = -1; i <= IPL_LOGMAX; i++) {
813 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
814 while ((iph = softh->ipf_htables[i + 1]) != NULL) {
815 if (ipf_htable_remove(softc, arg, iph) == 0) {
816 freed++;
817 } else {
818 iph->iph_flags |= IPHASH_DELETE;
819 }
820 }
821 }
822 }
823
824 return (freed);
825 }
826
827
828 /* ------------------------------------------------------------------------ */
829 /* Function: ipf_htable_node_add */
830 /* Returns: int - 0 = success, else error */
831 /* Parameters: softc(I) - pointer to soft context main structure */
832 /* arg(I) - pointer to local context to use */
833 /* op(I) - pointer to lookup operation data */
834 /* uid(I) - real uid of process doing operation */
835 /* */
836 /* ------------------------------------------------------------------------ */
837 static int
ipf_htable_node_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)838 ipf_htable_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
839 int uid)
840 {
841 iphtable_t *iph;
842 iphtent_t hte;
843 int err;
844
845 if (op->iplo_size != sizeof(hte)) {
846 IPFERROR(30018);
847 return (EINVAL);
848 }
849
850 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
851 if (err != 0) {
852 IPFERROR(30019);
853 return (EFAULT);
854 }
855 hte.ipe_uid = uid;
856
857 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
858 if (iph == NULL) {
859 IPFERROR(30020);
860 return (ESRCH);
861 }
862
863 if (ipf_htent_find(iph, &hte) != NULL) {
864 IPFERROR(30021);
865 return (EEXIST);
866 }
867
868 err = ipf_htent_insert(softc, arg, iph, &hte);
869
870 return (err);
871 }
872
873
874 /* ------------------------------------------------------------------------ */
875 /* Function: ipf_htent_insert */
876 /* Returns: int - 0 = success, -1 = error */
877 /* Parameters: softc(I) - pointer to soft context main structure */
878 /* arg(I) - pointer to local context to use */
879 /* op(I) - pointer to lookup operation data */
880 /* ipeo(I) - */
881 /* */
882 /* Add an entry to a hash table. */
883 /* ------------------------------------------------------------------------ */
884 static int
ipf_htent_insert(ipf_main_softc_t * softc,void * arg,iphtable_t * iph,iphtent_t * ipeo)885 ipf_htent_insert(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
886 iphtent_t *ipeo)
887 {
888 ipf_htable_softc_t *softh = arg;
889 iphtent_t *ipe;
890 u_int hv;
891 int bits;
892
893 KMALLOC(ipe, iphtent_t *);
894 if (ipe == NULL)
895 return (-1);
896
897 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
898 ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
899 if (ipe->ipe_family == AF_INET) {
900 bits = count4bits(ipe->ipe_mask.in4_addr);
901 ipe->ipe_addr.i6[1] = 0;
902 ipe->ipe_addr.i6[2] = 0;
903 ipe->ipe_addr.i6[3] = 0;
904 ipe->ipe_mask.i6[1] = 0;
905 ipe->ipe_mask.i6[2] = 0;
906 ipe->ipe_mask.i6[3] = 0;
907 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
908 ipe->ipe_mask.in4_addr, iph->iph_size);
909 } else
910 #ifdef USE_INET6
911 if (ipe->ipe_family == AF_INET6) {
912 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
913 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
914 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
915
916 bits = count6bits(ipe->ipe_mask.i6);
917 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
918 ipe->ipe_mask.i6, iph->iph_size);
919 } else
920 #endif
921 {
922 KFREE(ipe);
923 return (-1);
924 }
925
926 ipe->ipe_owner = iph;
927 ipe->ipe_ref = 1;
928 ipe->ipe_hnext = iph->iph_table[hv];
929 ipe->ipe_phnext = iph->iph_table + hv;
930
931 if (iph->iph_table[hv] != NULL)
932 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
933 iph->iph_table[hv] = ipe;
934
935 ipe->ipe_pnext = iph->iph_tail;
936 *iph->iph_tail = ipe;
937 iph->iph_tail = &ipe->ipe_next;
938 ipe->ipe_next = NULL;
939
940 if (ipe->ipe_die != 0) {
941 /*
942 * If the new node has a given expiration time, insert it
943 * into the list of expiring nodes with the ones to be
944 * removed first added to the front of the list. The
945 * insertion is O(n) but it is kept sorted for quick scans
946 * at expiration interval checks.
947 */
948 iphtent_t *n;
949
950 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
951 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
952 if (ipe->ipe_die < n->ipe_die)
953 break;
954 if (n->ipe_dnext == NULL) {
955 /*
956 * We've got to the last node and everything
957 * wanted to be expired before this new node,
958 * so we have to tack it on the end...
959 */
960 n->ipe_dnext = ipe;
961 ipe->ipe_pdnext = &n->ipe_dnext;
962 n = NULL;
963 break;
964 }
965 }
966
967 if (softh->ipf_node_explist == NULL) {
968 softh->ipf_node_explist = ipe;
969 ipe->ipe_pdnext = &softh->ipf_node_explist;
970 } else if (n != NULL) {
971 ipe->ipe_dnext = n;
972 ipe->ipe_pdnext = n->ipe_pdnext;
973 n->ipe_pdnext = &ipe->ipe_dnext;
974 }
975 }
976
977 if (ipe->ipe_family == AF_INET) {
978 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
979 }
980 #ifdef USE_INET6
981 else if (ipe->ipe_family == AF_INET6) {
982 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
983 }
984 #endif
985
986 switch (iph->iph_type & ~IPHASH_ANON)
987 {
988 case IPHASH_GROUPMAP :
989 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
990 iph->iph_flags, IPL_LOGIPF,
991 softc->ipf_active);
992 break;
993
994 default :
995 ipe->ipe_ptr = NULL;
996 ipe->ipe_value = 0;
997 break;
998 }
999
1000 ipe->ipe_unit = iph->iph_unit;
1001 softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1002
1003 return (0);
1004 }
1005
1006
1007 /* ------------------------------------------------------------------------ */
1008 /* Function: ipf_htent_find */
1009 /* Returns: int - 0 = success, else error */
1010 /* Parameters: iph(I) - pointer to table to search */
1011 /* ipeo(I) - pointer to entry to find */
1012 /* */
1013 /* While it isn't absolutely necessary to for the address and mask to be */
1014 /* passed in through an iphtent_t structure, one is always present when it */
1015 /* is time to call this function, so it is just more convenient. */
1016 /* ------------------------------------------------------------------------ */
1017 static iphtent_t *
ipf_htent_find(iphtable_t * iph,iphtent_t * ipeo)1018 ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
1019 {
1020 iphtent_t ipe, *ent;
1021 u_int hv;
1022
1023 bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1024 ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1025 ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1026 ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1027 ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1028 if (ipe.ipe_family == AF_INET) {
1029 ipe.ipe_addr.i6[1] = 0;
1030 ipe.ipe_addr.i6[2] = 0;
1031 ipe.ipe_addr.i6[3] = 0;
1032 ipe.ipe_mask.i6[1] = 0;
1033 ipe.ipe_mask.i6[2] = 0;
1034 ipe.ipe_mask.i6[3] = 0;
1035 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1036 ipe.ipe_mask.in4_addr, iph->iph_size);
1037 } else
1038 #ifdef USE_INET6
1039 if (ipe.ipe_family == AF_INET6) {
1040 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1041 ipe.ipe_mask.i6, iph->iph_size);
1042 } else
1043 #endif
1044 return (NULL);
1045
1046 for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1047 if (ent->ipe_family != ipe.ipe_family)
1048 continue;
1049 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1050 continue;
1051 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1052 continue;
1053 break;
1054 }
1055
1056 return (ent);
1057 }
1058
1059
1060 /* ------------------------------------------------------------------------ */
1061 /* Function: ipf_iphmfindgroup */
1062 /* Returns: int - 0 = success, else error */
1063 /* Parameters: softc(I) - pointer to soft context main structure */
1064 /* tptr(I) - */
1065 /* aptr(I) - */
1066 /* */
1067 /* Search a hash table for a matching entry and return the pointer stored */
1068 /* in it for use as the next group of rules to search. */
1069 /* */
1070 /* This function is exposed becaues it is used in the group-map feature. */
1071 /* ------------------------------------------------------------------------ */
1072 void *
ipf_iphmfindgroup(ipf_main_softc_t * softc,void * tptr,void * aptr)1073 ipf_iphmfindgroup(ipf_main_softc_t *softc, void *tptr, void *aptr)
1074 {
1075 struct in_addr *addr;
1076 iphtable_t *iph;
1077 iphtent_t *ipe;
1078 void *rval;
1079
1080 READ_ENTER(&softc->ipf_poolrw);
1081 iph = tptr;
1082 addr = aptr;
1083
1084 ipe = ipf_iphmfind(iph, addr);
1085 if (ipe != NULL)
1086 rval = ipe->ipe_ptr;
1087 else
1088 rval = NULL;
1089 RWLOCK_EXIT(&softc->ipf_poolrw);
1090 return (rval);
1091 }
1092
1093
1094 /* ------------------------------------------------------------------------ */
1095 /* Function: ipf_iphmfindip */
1096 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
1097 /* Parameters: softc(I) - pointer to soft context main structure */
1098 /* tptr(I) - pointer to the pool to search */
1099 /* ipversion(I) - IP protocol version (4 or 6) */
1100 /* aptr(I) - pointer to address information */
1101 /* bytes(I) - packet length */
1102 /* */
1103 /* Search the hash table for a given address and return a search result. */
1104 /* ------------------------------------------------------------------------ */
1105 static int
ipf_iphmfindip(ipf_main_softc_t * softc,void * tptr,int ipversion,void * aptr,u_int bytes)1106 ipf_iphmfindip(ipf_main_softc_t *softc, void *tptr, int ipversion, void *aptr,
1107 u_int bytes)
1108 {
1109 struct in_addr *addr;
1110 iphtable_t *iph;
1111 iphtent_t *ipe;
1112 int rval;
1113
1114 if (tptr == NULL || aptr == NULL)
1115 return (-1);
1116
1117 iph = tptr;
1118 addr = aptr;
1119
1120 READ_ENTER(&softc->ipf_poolrw);
1121 if (ipversion == 4) {
1122 ipe = ipf_iphmfind(iph, addr);
1123 #ifdef USE_INET6
1124 } else if (ipversion == 6) {
1125 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1126 #endif
1127 } else {
1128 ipe = NULL;
1129 }
1130
1131 if (ipe != NULL) {
1132 rval = 0;
1133 ipe->ipe_hits++;
1134 ipe->ipe_bytes += bytes;
1135 } else {
1136 rval = 1;
1137 }
1138 RWLOCK_EXIT(&softc->ipf_poolrw);
1139 return (rval);
1140 }
1141
1142
1143 /* ------------------------------------------------------------------------ */
1144 /* Function: ipf_iphmfindip */
1145 /* Parameters: iph(I) - pointer to hash table */
1146 /* addr(I) - pointer to IPv4 address */
1147 /* Locks: ipf_poolrw */
1148 /* */
1149 /* ------------------------------------------------------------------------ */
1150 static iphtent_t *
ipf_iphmfind(iphtable_t * iph,struct in_addr * addr)1151 ipf_iphmfind(iphtable_t *iph, struct in_addr *addr)
1152 {
1153 u_32_t msk, ips;
1154 iphtent_t *ipe;
1155 u_int hv;
1156 int i;
1157
1158 i = 0;
1159 maskloop:
1160 msk = iph->iph_v4_masks.imt4_active[i];
1161 ips = addr->s_addr & msk;
1162 hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1163 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1164 if ((ipe->ipe_family != AF_INET) ||
1165 (ipe->ipe_mask.in4_addr != msk) ||
1166 (ipe->ipe_addr.in4_addr != ips)) {
1167 continue;
1168 }
1169 break;
1170 }
1171
1172 if (ipe == NULL) {
1173 i++;
1174 if (i < iph->iph_v4_masks.imt4_max)
1175 goto maskloop;
1176 }
1177 return (ipe);
1178 }
1179
1180
1181 /* ------------------------------------------------------------------------ */
1182 /* Function: ipf_htable_iter_next */
1183 /* Returns: int - 0 = success, else error */
1184 /* Parameters: softc(I) - pointer to soft context main structure */
1185 /* arg(I) - pointer to local context to use */
1186 /* token(I) - */
1187 /* ilp(I) - */
1188 /* */
1189 /* ------------------------------------------------------------------------ */
1190 static int
ipf_htable_iter_next(ipf_main_softc_t * softc,void * arg,ipftoken_t * token,ipflookupiter_t * ilp)1191 ipf_htable_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
1192 ipflookupiter_t *ilp)
1193 {
1194 ipf_htable_softc_t *softh = arg;
1195 iphtent_t *node, zn, *nextnode;
1196 iphtable_t *iph, zp, *nextiph;
1197 void *hnext;
1198 int err;
1199
1200 err = 0;
1201 iph = NULL;
1202 node = NULL;
1203 nextiph = NULL;
1204 nextnode = NULL;
1205
1206 READ_ENTER(&softc->ipf_poolrw);
1207
1208 switch (ilp->ili_otype)
1209 {
1210 case IPFLOOKUPITER_LIST :
1211 iph = token->ipt_data;
1212 if (iph == NULL) {
1213 nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1214 } else {
1215 nextiph = iph->iph_next;
1216 }
1217
1218 if (nextiph != NULL) {
1219 ATOMIC_INC(nextiph->iph_ref);
1220 token->ipt_data = nextiph;
1221 } else {
1222 bzero((char *)&zp, sizeof(zp));
1223 nextiph = &zp;
1224 token->ipt_data = NULL;
1225 }
1226 hnext = nextiph->iph_next;
1227 break;
1228
1229 case IPFLOOKUPITER_NODE :
1230 node = token->ipt_data;
1231 if (node == NULL) {
1232 iph = ipf_htable_find(arg, ilp->ili_unit,
1233 ilp->ili_name);
1234 if (iph == NULL) {
1235 IPFERROR(30009);
1236 err = ESRCH;
1237 } else {
1238 nextnode = iph->iph_list;
1239 }
1240 } else {
1241 nextnode = node->ipe_next;
1242 }
1243
1244 if (nextnode != NULL) {
1245 ATOMIC_INC(nextnode->ipe_ref);
1246 token->ipt_data = nextnode;
1247 } else {
1248 bzero((char *)&zn, sizeof(zn));
1249 nextnode = &zn;
1250 token->ipt_data = NULL;
1251 }
1252 hnext = nextnode->ipe_next;
1253 break;
1254
1255 default :
1256 IPFERROR(30010);
1257 err = EINVAL;
1258 hnext = NULL;
1259 break;
1260 }
1261
1262 RWLOCK_EXIT(&softc->ipf_poolrw);
1263 if (err != 0)
1264 return (err);
1265
1266 switch (ilp->ili_otype)
1267 {
1268 case IPFLOOKUPITER_LIST :
1269 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1270 if (err != 0) {
1271 IPFERROR(30011);
1272 err = EFAULT;
1273 }
1274 if (iph != NULL) {
1275 WRITE_ENTER(&softc->ipf_poolrw);
1276 ipf_htable_deref(softc, softh, iph);
1277 RWLOCK_EXIT(&softc->ipf_poolrw);
1278 }
1279 break;
1280
1281 case IPFLOOKUPITER_NODE :
1282 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1283 if (err != 0) {
1284 IPFERROR(30012);
1285 err = EFAULT;
1286 }
1287 if (node != NULL) {
1288 WRITE_ENTER(&softc->ipf_poolrw);
1289 ipf_htent_deref(softc, node);
1290 RWLOCK_EXIT(&softc->ipf_poolrw);
1291 }
1292 break;
1293 }
1294
1295 if (hnext == NULL)
1296 ipf_token_mark_complete(token);
1297
1298 return (err);
1299 }
1300
1301
1302 /* ------------------------------------------------------------------------ */
1303 /* Function: ipf_htable_iter_deref */
1304 /* Returns: int - 0 = success, else error */
1305 /* Parameters: softc(I) - pointer to soft context main structure */
1306 /* arg(I) - pointer to local context to use */
1307 /* otype(I) - which data structure type is being walked */
1308 /* unit(I) - ipfilter device to which we are working on */
1309 /* data(I) - pointer to old data structure */
1310 /* */
1311 /* ------------------------------------------------------------------------ */
1312 static int
ipf_htable_iter_deref(ipf_main_softc_t * softc,void * arg,int otype,int unit,void * data)1313 ipf_htable_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
1314 void *data)
1315 {
1316
1317 if (data == NULL)
1318 return (EFAULT);
1319
1320 if (unit < -1 || unit > IPL_LOGMAX)
1321 return (EINVAL);
1322
1323 switch (otype)
1324 {
1325 case IPFLOOKUPITER_LIST :
1326 ipf_htable_deref(softc, arg, (iphtable_t *)data);
1327 break;
1328
1329 case IPFLOOKUPITER_NODE :
1330 ipf_htent_deref(arg, (iphtent_t *)data);
1331 break;
1332 default :
1333 break;
1334 }
1335
1336 return (0);
1337 }
1338
1339
1340 #ifdef USE_INET6
1341 /* ------------------------------------------------------------------------ */
1342 /* Function: ipf_iphmfind6 */
1343 /* Parameters: iph(I) - pointer to hash table */
1344 /* addr(I) - pointer to IPv6 address */
1345 /* Locks: ipf_poolrw */
1346 /* */
1347 /* ------------------------------------------------------------------------ */
1348 static iphtent_t *
ipf_iphmfind6(iphtable_t * iph,i6addr_t * addr)1349 ipf_iphmfind6(iphtable_t *iph, i6addr_t *addr)
1350 {
1351 i6addr_t *msk, ips;
1352 iphtent_t *ipe;
1353 u_int hv;
1354 int i;
1355
1356 i = 0;
1357 maskloop:
1358 msk = iph->iph_v6_masks.imt6_active + i;
1359 ips.i6[0] = addr->i6[0] & msk->i6[0];
1360 ips.i6[1] = addr->i6[1] & msk->i6[1];
1361 ips.i6[2] = addr->i6[2] & msk->i6[2];
1362 ips.i6[3] = addr->i6[3] & msk->i6[3];
1363 hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1364 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1365 if ((ipe->ipe_family != AF_INET6) ||
1366 IP6_NEQ(&ipe->ipe_mask, msk) ||
1367 IP6_NEQ(&ipe->ipe_addr, &ips)) {
1368 continue;
1369 }
1370 break;
1371 }
1372
1373 if (ipe == NULL) {
1374 i++;
1375 if (i < iph->iph_v6_masks.imt6_max)
1376 goto maskloop;
1377 }
1378 return (ipe);
1379 }
1380 #endif
1381
1382
1383 static void
ipf_htable_expire(ipf_main_softc_t * softc,void * arg)1384 ipf_htable_expire(ipf_main_softc_t *softc, void *arg)
1385 {
1386 ipf_htable_softc_t *softh = arg;
1387 iphtent_t *n;
1388
1389 while ((n = softh->ipf_node_explist) != NULL) {
1390 if (n->ipe_die > softc->ipf_ticks)
1391 break;
1392
1393 ipf_htent_remove(softc, softh, n->ipe_owner, n);
1394 }
1395 }
1396
1397
1398 #ifndef _KERNEL
1399
1400 /* ------------------------------------------------------------------------ */
1401 /* */
1402 /* ------------------------------------------------------------------------ */
1403 void
ipf_htable_dump(ipf_main_softc_t * softc,void * arg)1404 ipf_htable_dump(ipf_main_softc_t *softc, void *arg)
1405 {
1406 ipf_htable_softc_t *softh = arg;
1407 iphtable_t *iph;
1408 int i;
1409
1410 printf("List of configured hash tables\n");
1411 for (i = 0; i < IPL_LOGSIZE; i++)
1412 for (iph = softh->ipf_htables[i]; iph != NULL;
1413 iph = iph->iph_next)
1414 printhash(iph, bcopywrap, NULL, opts, NULL);
1415
1416 }
1417 #endif
1418