xref: /freebsd/sys/netpfil/ipfilter/netinet/ip_htable.c (revision df381bec2d2b73697a3d163177df042dd272022d)
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