1 /* $NetBSD: ip_dstlist.c,v 1.8 2014/06/28 07:59:26 darrenr Exp $ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define KERNEL 1
12 # define _KERNEL 1
13 #endif
14 #if defined(__osf__)
15 # define _PROTO_NET_H_
16 #endif
17 #include <sys/errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #if !defined(_KERNEL) && !defined(__KERNEL__)
22 # include <stdio.h>
23 # include <stdlib.h>
24 # include <string.h>
25 # define _KERNEL
26 # ifdef __OpenBSD__
27 struct file;
28 # endif
29 # include <sys/uio.h>
30 # undef _KERNEL
31 #else
32 # include <sys/systm.h>
33 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
34 # include <sys/proc.h>
35 # endif
36 #endif
37 #include <sys/time.h>
38 #if !defined(linux)
39 # include <sys/protosw.h>
40 #endif
41 #include <sys/socket.h>
42 #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
43 # include <sys/mbuf.h>
44 #endif
45 #if defined(__SVR4) || defined(__svr4__)
46 # include <sys/filio.h>
47 # include <sys/byteorder.h>
48 # ifdef _KERNEL
49 # include <sys/dditypes.h>
50 # endif
51 # include <sys/stream.h>
52 # include <sys/kmem.h>
53 #endif
54 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
55 # include <sys/malloc.h>
56 #endif
57
58 #include <net/if.h>
59 #include <netinet/in.h>
60
61 #include "netinet/ip_compat.h"
62 #include "netinet/ip_fil.h"
63 #include "netinet/ip_nat.h"
64 #include "netinet/ip_lookup.h"
65 #include "netinet/ip_dstlist.h"
66
67 /* END OF INCLUDES */
68
69 #ifdef HAS_SYS_MD5_H
70 # include <sys/md5.h>
71 #else
72 # include "md5.h"
73 #endif
74
75 __KERNEL_RCSID(0, "Id: ip_dstlist.c,v 1.1.1.2 2012/07/22 13:45:11 darrenr Exp");
76
77 typedef struct ipf_dstl_softc_s {
78 ippool_dst_t *dstlist[LOOKUP_POOL_SZ];
79 ippool_dst_t **tails[LOOKUP_POOL_SZ];
80 ipf_dstl_stat_t stats;
81 } ipf_dstl_softc_t;
82
83
84 static void *ipf_dstlist_soft_create(ipf_main_softc_t *);
85 static void ipf_dstlist_soft_destroy(ipf_main_softc_t *, void *);
86 static int ipf_dstlist_soft_init(ipf_main_softc_t *, void *);
87 static void ipf_dstlist_soft_fini(ipf_main_softc_t *, void *);
88 static int ipf_dstlist_addr_find(ipf_main_softc_t *, void *, int,
89 void *, u_int);
90 static size_t ipf_dstlist_flush(ipf_main_softc_t *, void *,
91 iplookupflush_t *);
92 static void ipf_dstlist_table_free(ipf_dstl_softc_t *, ippool_dst_t *);
93 static int ipf_dstlist_iter_deref(ipf_main_softc_t *, void *, int, int,
94 void *);
95 static int ipf_dstlist_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
96 ipflookupiter_t *);
97 static int ipf_dstlist_node_add(ipf_main_softc_t *, void *,
98 iplookupop_t *, int);
99 static int ipf_dstlist_node_del(ipf_main_softc_t *, void *,
100 iplookupop_t *, int);
101 static int ipf_dstlist_stats_get(ipf_main_softc_t *, void *,
102 iplookupop_t *);
103 static int ipf_dstlist_table_add(ipf_main_softc_t *, void *,
104 iplookupop_t *);
105 static int ipf_dstlist_table_del(ipf_main_softc_t *, void *,
106 iplookupop_t *);
107 static int ipf_dstlist_table_deref(ipf_main_softc_t *, void *, void *);
108 static void *ipf_dstlist_table_find(void *, int, char *);
109 static void ipf_dstlist_table_remove(ipf_main_softc_t *,
110 ipf_dstl_softc_t *, ippool_dst_t *);
111 static void ipf_dstlist_table_clearnodes(ipf_dstl_softc_t *,
112 ippool_dst_t *);
113 static ipf_dstnode_t *ipf_dstlist_select(fr_info_t *, ippool_dst_t *);
114 static void *ipf_dstlist_select_ref(void *, int, char *);
115 static void ipf_dstlist_node_free(ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *);
116 static int ipf_dstlist_node_deref(void *, ipf_dstnode_t *);
117 static void ipf_dstlist_expire(ipf_main_softc_t *, void *);
118 static void ipf_dstlist_sync(ipf_main_softc_t *, void *);
119
120 ipf_lookup_t ipf_dstlist_backend = {
121 IPLT_DSTLIST,
122 ipf_dstlist_soft_create,
123 ipf_dstlist_soft_destroy,
124 ipf_dstlist_soft_init,
125 ipf_dstlist_soft_fini,
126 ipf_dstlist_addr_find,
127 ipf_dstlist_flush,
128 ipf_dstlist_iter_deref,
129 ipf_dstlist_iter_next,
130 ipf_dstlist_node_add,
131 ipf_dstlist_node_del,
132 ipf_dstlist_stats_get,
133 ipf_dstlist_table_add,
134 ipf_dstlist_table_del,
135 ipf_dstlist_table_deref,
136 ipf_dstlist_table_find,
137 ipf_dstlist_select_ref,
138 ipf_dstlist_select_node,
139 ipf_dstlist_expire,
140 ipf_dstlist_sync
141 };
142
143
144 /* ------------------------------------------------------------------------ */
145 /* Function: ipf_dstlist_soft_create */
146 /* Returns: int - 0 = success, else error */
147 /* Parameters: softc(I) - pointer to soft context main structure */
148 /* */
149 /* Allocating a chunk of memory filled with 0's is enough for the current */
150 /* soft context used with destination lists. */
151 /* ------------------------------------------------------------------------ */
152 static void *
ipf_dstlist_soft_create(ipf_main_softc_t * softc)153 ipf_dstlist_soft_create(ipf_main_softc_t *softc)
154 {
155 ipf_dstl_softc_t *softd;
156 int i;
157
158 KMALLOC(softd, ipf_dstl_softc_t *);
159 if (softd == NULL) {
160 IPFERROR(120028);
161 return NULL;
162 }
163
164 bzero((char *)softd, sizeof(*softd));
165 for (i = 0; i <= IPL_LOGMAX; i++)
166 softd->tails[i] = &softd->dstlist[i];
167
168 return softd;
169 }
170
171
172 /* ------------------------------------------------------------------------ */
173 /* Function: ipf_dstlist_soft_destroy */
174 /* Returns: Nil */
175 /* Parameters: softc(I) - pointer to soft context main structure */
176 /* arg(I) - pointer to local context to use */
177 /* */
178 /* For destination lists, the only thing we have to do when destroying the */
179 /* soft context is free it! */
180 /* ------------------------------------------------------------------------ */
181 static void
ipf_dstlist_soft_destroy(ipf_main_softc_t * softc,void * arg)182 ipf_dstlist_soft_destroy(ipf_main_softc_t *softc, void *arg)
183 {
184 ipf_dstl_softc_t *softd = arg;
185
186 KFREE(softd);
187 }
188
189
190 /* ------------------------------------------------------------------------ */
191 /* Function: ipf_dstlist_soft_init */
192 /* Returns: int - 0 = success, else error */
193 /* Parameters: softc(I) - pointer to soft context main structure */
194 /* arg(I) - pointer to local context to use */
195 /* */
196 /* There is currently no soft context for destination list management. */
197 /* ------------------------------------------------------------------------ */
198 static int
ipf_dstlist_soft_init(ipf_main_softc_t * softc,void * arg)199 ipf_dstlist_soft_init(ipf_main_softc_t *softc, void *arg)
200 {
201 return 0;
202 }
203
204
205 /* ------------------------------------------------------------------------ */
206 /* Function: ipf_dstlist_soft_fini */
207 /* Returns: Nil */
208 /* Parameters: softc(I) - pointer to soft context main structure */
209 /* arg(I) - pointer to local context to use */
210 /* */
211 /* There is currently no soft context for destination list management. */
212 /* ------------------------------------------------------------------------ */
213 static void
ipf_dstlist_soft_fini(ipf_main_softc_t * softc,void * arg)214 ipf_dstlist_soft_fini(ipf_main_softc_t *softc, void *arg)
215 {
216 ipf_dstl_softc_t *softd = arg;
217 int i;
218
219 for (i = -1; i <= IPL_LOGMAX; i++) {
220 while (softd->dstlist[i + 1] != NULL) {
221 ipf_dstlist_table_remove(softc, softd,
222 softd->dstlist[i + 1]);
223 }
224 }
225
226 ASSERT(softd->stats.ipls_numderefnodes == 0);
227 }
228
229
230 /* ------------------------------------------------------------------------ */
231 /* Function: ipf_dstlist_addr_find */
232 /* Returns: int - 0 = success, else error */
233 /* Parameters: softc(I) - pointer to soft context main structure */
234 /* arg1(I) - pointer to local context to use */
235 /* arg2(I) - pointer to local context to use */
236 /* arg3(I) - pointer to local context to use */
237 /* arg4(I) - pointer to local context to use */
238 /* */
239 /* There is currently no such thing as searching a destination list for an */
240 /* address so this function becomes a no-op. Its presence is required as */
241 /* ipf_lookup_res_name() stores the "addr_find" function pointer in the */
242 /* pointer passed in to it as funcptr, although it could be a generic null- */
243 /* op function rather than a specific one. */
244 /* ------------------------------------------------------------------------ */
245 /*ARGSUSED*/
246 static int
ipf_dstlist_addr_find(ipf_main_softc_t * softc,void * arg1,int arg2,void * arg3,u_int arg4)247 ipf_dstlist_addr_find(ipf_main_softc_t *softc, void *arg1, int arg2, void *arg3,
248 u_int arg4)
249 {
250 return -1;
251 }
252
253
254 /* ------------------------------------------------------------------------ */
255 /* Function: ipf_dstlist_flush */
256 /* Returns: int - number of objects deleted */
257 /* Parameters: softc(I) - pointer to soft context main structure */
258 /* arg(I) - pointer to local context to use */
259 /* fop(I) - pointer to lookup flush operation data */
260 /* */
261 /* Flush all of the destination tables that match the data passed in with */
262 /* the iplookupflush_t. There are two ways to match objects: the device for */
263 /* which they are to be used with and their name. */
264 /* ------------------------------------------------------------------------ */
265 static size_t
ipf_dstlist_flush(ipf_main_softc_t * softc,void * arg,iplookupflush_t * fop)266 ipf_dstlist_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *fop)
267 {
268 ipf_dstl_softc_t *softd = arg;
269 ippool_dst_t *node, *next;
270 int n, i;
271
272 for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
273 if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
274 continue;
275 for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
276 next = node->ipld_next;
277
278 if ((*fop->iplf_name != '\0') &&
279 strncmp(fop->iplf_name, node->ipld_name,
280 FR_GROUPLEN))
281 continue;
282
283 ipf_dstlist_table_remove(softc, softd, node);
284 n++;
285 }
286 }
287 return n;
288 }
289
290
291 /* ------------------------------------------------------------------------ */
292 /* Function: ipf_dstlist_iter_deref */
293 /* Returns: int - 0 = success, else error */
294 /* Parameters: softc(I) - pointer to soft context main structure */
295 /* arg(I) - pointer to local context to use */
296 /* otype(I) - type of data structure to iterate through */
297 /* unit(I) - device we are working with */
298 /* data(I) - address of object in kernel space */
299 /* */
300 /* This function is called when the iteration token is being free'd and is */
301 /* responsible for dropping the reference count of the structure it points */
302 /* to. */
303 /* ------------------------------------------------------------------------ */
304 static int
ipf_dstlist_iter_deref(ipf_main_softc_t * softc,void * arg,int otype,int unit,void * data)305 ipf_dstlist_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
306 void *data)
307 {
308 if (data == NULL) {
309 IPFERROR(120001);
310 return EINVAL;
311 }
312
313 if (unit < -1 || unit > IPL_LOGMAX) {
314 IPFERROR(120002);
315 return EINVAL;
316 }
317
318 switch (otype)
319 {
320 case IPFLOOKUPITER_LIST :
321 ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
322 break;
323
324 case IPFLOOKUPITER_NODE :
325 ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
326 break;
327 }
328
329 return 0;
330 }
331
332
333 /* ------------------------------------------------------------------------ */
334 /* Function: ipf_dstlist_iter_next */
335 /* Returns: int - 0 = success, else error */
336 /* Parameters: softc(I) - pointer to soft context main structure */
337 /* arg(I) - pointer to local context to use */
338 /* op(I) - pointer to lookup operation data */
339 /* uid(I) - uid of process doing the ioctl */
340 /* */
341 /* This function is responsible for either selecting the next destination */
342 /* list or node on a destination list to be returned as a user process */
343 /* iterates through the list of destination lists or nodes. */
344 /* ------------------------------------------------------------------------ */
345 static int
ipf_dstlist_iter_next(ipf_main_softc_t * softc,void * arg,ipftoken_t * token,ipflookupiter_t * iter)346 ipf_dstlist_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
347 ipflookupiter_t *iter)
348 {
349 ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
350 ippool_dst_t zero, *next = NULL, *dsttab = NULL;
351 ipf_dstl_softc_t *softd = arg;
352 int err = 0;
353 void *hint;
354
355 switch (iter->ili_otype)
356 {
357 case IPFLOOKUPITER_LIST :
358 dsttab = token->ipt_data;
359 if (dsttab == NULL) {
360 next = softd->dstlist[(int)iter->ili_unit + 1];
361 } else {
362 next = dsttab->ipld_next;
363 }
364
365 if (next != NULL) {
366 ATOMIC_INC32(next->ipld_ref);
367 token->ipt_data = next;
368 hint = next->ipld_next;
369 } else {
370 bzero((char *)&zero, sizeof(zero));
371 next = &zero;
372 token->ipt_data = NULL;
373 hint = NULL;
374 }
375 break;
376
377 case IPFLOOKUPITER_NODE :
378 node = token->ipt_data;
379 if (node == NULL) {
380 dsttab = ipf_dstlist_table_find(arg, iter->ili_unit,
381 iter->ili_name);
382 if (dsttab == NULL) {
383 IPFERROR(120004);
384 err = ESRCH;
385 nextnode = NULL;
386 } else {
387 if (dsttab->ipld_dests == NULL)
388 nextnode = NULL;
389 else
390 nextnode = *dsttab->ipld_dests;
391 dsttab = NULL;
392 }
393 } else {
394 nextnode = node->ipfd_next;
395 }
396
397 if (nextnode != NULL) {
398 MUTEX_ENTER(&nextnode->ipfd_lock);
399 nextnode->ipfd_ref++;
400 MUTEX_EXIT(&nextnode->ipfd_lock);
401 token->ipt_data = nextnode;
402 hint = nextnode->ipfd_next;
403 } else {
404 bzero((char *)&zn, sizeof(zn));
405 nextnode = &zn;
406 token->ipt_data = NULL;
407 hint = NULL;
408 }
409 break;
410 default :
411 IPFERROR(120003);
412 err = EINVAL;
413 break;
414 }
415
416 if (err != 0)
417 return err;
418
419 switch (iter->ili_otype)
420 {
421 case IPFLOOKUPITER_LIST :
422 if (dsttab != NULL)
423 ipf_dstlist_table_deref(softc, arg, dsttab);
424 err = COPYOUT(next, iter->ili_data, sizeof(*next));
425 if (err != 0) {
426 IPFERROR(120005);
427 err = EFAULT;
428 }
429 break;
430
431 case IPFLOOKUPITER_NODE :
432 if (node != NULL)
433 ipf_dstlist_node_deref(arg, node);
434 err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
435 if (err != 0) {
436 IPFERROR(120006);
437 err = EFAULT;
438 }
439 break;
440 }
441
442 if (hint == NULL)
443 ipf_token_mark_complete(token);
444
445 return err;
446 }
447
448
449 /* ------------------------------------------------------------------------ */
450 /* Function: ipf_dstlist_node_add */
451 /* Returns: int - 0 = success, else error */
452 /* Parameters: softc(I) - pointer to soft context main structure */
453 /* arg(I) - pointer to local context to use */
454 /* op(I) - pointer to lookup operation data */
455 /* uid(I) - uid of process doing the ioctl */
456 /* Locks: WRITE(ipf_poolrw) */
457 /* */
458 /* Add a new node to a destination list. To do this, we only copy in the */
459 /* frdest_t structure because that contains the only data required from the */
460 /* application to create a new node. The frdest_t doesn't contain the name */
461 /* itself. When loading filter rules, fd_name is a 'pointer' to the name. */
462 /* In this case, the 'pointer' does not work, instead it is the length of */
463 /* the name and the name is immediately following the frdest_t structure. */
464 /* fd_name must include the trailing \0, so it should be strlen(str) + 1. */
465 /* For simple sanity checking, an upper bound on the size of fd_name is */
466 /* imposed - 128. */
467 /* ------------------------------------------------------------------------ */
468 static int
ipf_dstlist_node_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)469 ipf_dstlist_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
470 int uid)
471 {
472 ipf_dstl_softc_t *softd = arg;
473 ipf_dstnode_t *node, **nodes;
474 ippool_dst_t *d;
475 frdest_t dest;
476 int err;
477
478 if (op->iplo_size < sizeof(frdest_t)) {
479 IPFERROR(120007);
480 return EINVAL;
481 }
482
483 err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
484 if (err != 0) {
485 IPFERROR(120009);
486 return EFAULT;
487 }
488
489 d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
490 if (d == NULL) {
491 IPFERROR(120010);
492 return ESRCH;
493 }
494
495 switch (dest.fd_addr.adf_family)
496 {
497 case AF_INET :
498 case AF_INET6 :
499 break;
500 default :
501 IPFERROR(120019);
502 return EINVAL;
503 }
504
505 if (dest.fd_name < -1 || dest.fd_name > 128) {
506 IPFERROR(120018);
507 return EINVAL;
508 }
509
510 KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
511 if (node == NULL) {
512 softd->stats.ipls_nomem++;
513 IPFERROR(120008);
514 return ENOMEM;
515 }
516 bzero((char *)node, sizeof(*node) + dest.fd_name);
517
518 bcopy(&dest, &node->ipfd_dest, sizeof(dest));
519 node->ipfd_size = sizeof(*node) + dest.fd_name;
520
521 if (dest.fd_name > 0) {
522 /*
523 * fd_name starts out as the length of the string to copy
524 * in (including \0) and ends up being the offset from
525 * fd_names (0).
526 */
527 err = COPYIN((char *)op->iplo_struct + sizeof(dest),
528 node->ipfd_names, dest.fd_name);
529 if (err != 0) {
530 IPFERROR(120017);
531 KFREES(node, node->ipfd_size);
532 return EFAULT;
533 }
534 node->ipfd_dest.fd_name = 0;
535 } else {
536 node->ipfd_dest.fd_name = -1;
537 }
538
539 if (d->ipld_nodes == d->ipld_maxnodes) {
540 KMALLOCS(nodes, ipf_dstnode_t **,
541 sizeof(*nodes) * (d->ipld_maxnodes + 1));
542 if (nodes == NULL) {
543 softd->stats.ipls_nomem++;
544 IPFERROR(120022);
545 KFREES(node, node->ipfd_size);
546 return ENOMEM;
547 }
548 if (d->ipld_dests != NULL) {
549 bcopy(d->ipld_dests, nodes,
550 sizeof(*nodes) * d->ipld_maxnodes);
551 KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
552 nodes[0]->ipfd_pnext = nodes;
553 }
554 d->ipld_dests = nodes;
555 d->ipld_maxnodes++;
556 }
557 d->ipld_dests[d->ipld_nodes] = node;
558 d->ipld_nodes++;
559
560 if (d->ipld_nodes == 1) {
561 node->ipfd_pnext = d->ipld_dests;
562 } else if (d->ipld_nodes > 1) {
563 node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
564 }
565 *node->ipfd_pnext = node;
566
567 MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
568 node->ipfd_uid = uid;
569 node->ipfd_ref = 1;
570 if (node->ipfd_dest.fd_name == 0)
571 (void) ipf_resolvedest(softc, node->ipfd_names,
572 &node->ipfd_dest, AF_INET);
573 #ifdef USE_INET6
574 if (node->ipfd_dest.fd_name == 0 &&
575 node->ipfd_dest.fd_ptr == (void *)-1)
576 (void) ipf_resolvedest(softc, node->ipfd_names,
577 &node->ipfd_dest, AF_INET6);
578 #endif
579
580 softd->stats.ipls_numnodes++;
581
582 return 0;
583 }
584
585
586 /* ------------------------------------------------------------------------ */
587 /* Function: ipf_dstlist_node_deref */
588 /* Returns: int - 0 = success, else error */
589 /* Parameters: arg(I) - pointer to local context to use */
590 /* node(I) - pointer to destionation node to free */
591 /* */
592 /* Dereference the use count by one. If it drops to zero then we can assume */
593 /* that it has been removed from any lists/tables and is ripe for freeing. */
594 /* The pointer to context is required for the purpose of maintaining */
595 /* statistics. */
596 /* ------------------------------------------------------------------------ */
597 static int
ipf_dstlist_node_deref(void * arg,ipf_dstnode_t * node)598 ipf_dstlist_node_deref(void *arg, ipf_dstnode_t *node)
599 {
600 ipf_dstl_softc_t *softd = arg;
601 int ref;
602
603 MUTEX_ENTER(&node->ipfd_lock);
604 ref = --node->ipfd_ref;
605 MUTEX_EXIT(&node->ipfd_lock);
606
607 if (ref > 0)
608 return 0;
609
610 if ((node->ipfd_flags & IPDST_DELETE) != 0)
611 softd->stats.ipls_numderefnodes--;
612 MUTEX_DESTROY(&node->ipfd_lock);
613 KFREES(node, node->ipfd_size);
614 softd->stats.ipls_numnodes--;
615
616 return 0;
617 }
618
619
620 /* ------------------------------------------------------------------------ */
621 /* Function: ipf_dstlist_node_del */
622 /* Returns: int - 0 = success, else error */
623 /* Parameters: softc(I) - pointer to soft context main structure */
624 /* arg(I) - pointer to local context to use */
625 /* op(I) - pointer to lookup operation data */
626 /* uid(I) - uid of process doing the ioctl */
627 /* */
628 /* Look for a matching destination node on the named table and free it if */
629 /* found. Because the name embedded in the frdest_t is variable in length, */
630 /* it is necessary to allocate some memory locally, to complete this op. */
631 /* ------------------------------------------------------------------------ */
632 static int
ipf_dstlist_node_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)633 ipf_dstlist_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
634 int uid)
635 {
636 ipf_dstl_softc_t *softd = arg;
637 ipf_dstnode_t *node;
638 frdest_t frd, *temp;
639 ippool_dst_t *d;
640 size_t size;
641 int err;
642
643 d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
644 if (d == NULL) {
645 IPFERROR(120012);
646 return ESRCH;
647 }
648
649 err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
650 if (err != 0) {
651 IPFERROR(120011);
652 return EFAULT;
653 }
654
655 size = sizeof(*temp) + frd.fd_name;
656 KMALLOCS(temp, frdest_t *, size);
657 if (temp == NULL) {
658 softd->stats.ipls_nomem++;
659 IPFERROR(120026);
660 return ENOMEM;
661 }
662
663 err = COPYIN(op->iplo_struct, temp, size);
664 if (err != 0) {
665 IPFERROR(120027);
666 return EFAULT;
667 }
668
669 MUTEX_ENTER(&d->ipld_lock);
670 for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
671 if ((uid != 0) && (node->ipfd_uid != uid))
672 continue;
673 if (node->ipfd_size != size)
674 continue;
675 if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
676 size - offsetof(frdest_t, fd_ip6))) {
677 ipf_dstlist_node_free(softd, d, node);
678 MUTEX_EXIT(&d->ipld_lock);
679 KFREES(temp, size);
680 return 0;
681 }
682 }
683 MUTEX_EXIT(&d->ipld_lock);
684 KFREES(temp, size);
685
686 return ESRCH;
687 }
688
689
690 /* ------------------------------------------------------------------------ */
691 /* Function: ipf_dstlist_node_free */
692 /* Returns: Nil */
693 /* Parameters: softd(I) - pointer to the destination list context */
694 /* d(I) - pointer to destination list */
695 /* node(I) - pointer to node to free */
696 /* Locks: MUTEX(ipld_lock) or WRITE(ipf_poolrw) */
697 /* */
698 /* Free the destination node by first removing it from any lists and then */
699 /* checking if this was the last reference held to the object. While the */
700 /* array of pointers to nodes is compacted, its size isn't reduced (by way */
701 /* of allocating a new smaller one and copying) because the belief is that */
702 /* it is likely the array will again reach that size. */
703 /* ------------------------------------------------------------------------ */
704 static void
ipf_dstlist_node_free(ipf_dstl_softc_t * softd,ippool_dst_t * d,ipf_dstnode_t * node)705 ipf_dstlist_node_free(ipf_dstl_softc_t *softd, ippool_dst_t *d,
706 ipf_dstnode_t *node)
707 {
708 int i;
709
710 /*
711 * Compact the array of pointers to nodes.
712 */
713 for (i = 0; i < d->ipld_nodes; i++)
714 if (d->ipld_dests[i] == node)
715 break;
716 if (d->ipld_nodes - i > 1) {
717 bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
718 sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
719 }
720 d->ipld_nodes--;
721
722 if (node->ipfd_pnext != NULL)
723 *node->ipfd_pnext = node->ipfd_next;
724 if (node->ipfd_next != NULL)
725 node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
726 node->ipfd_pnext = NULL;
727 node->ipfd_next = NULL;
728
729 if ((node->ipfd_flags & IPDST_DELETE) == 0) {
730 softd->stats.ipls_numderefnodes++;
731 node->ipfd_flags |= IPDST_DELETE;
732 }
733
734 ipf_dstlist_node_deref(softd, node);
735 }
736
737
738 /* ------------------------------------------------------------------------ */
739 /* Function: ipf_dstlist_stats_get */
740 /* Returns: int - 0 = success, else error */
741 /* Parameters: softc(I) - pointer to soft context main structure */
742 /* arg(I) - pointer to local context to use */
743 /* op(I) - pointer to lookup operation data */
744 /* */
745 /* Return the current statistics for destination lists. This may be for all */
746 /* of them or just information pertaining to a particular table. */
747 /* ------------------------------------------------------------------------ */
748 /*ARGSUSED*/
749 static int
ipf_dstlist_stats_get(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)750 ipf_dstlist_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
751 {
752 ipf_dstl_softc_t *softd = arg;
753 ipf_dstl_stat_t stats;
754 int unit, i, err = 0;
755
756 if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
757 IPFERROR(120023);
758 return EINVAL;
759 }
760
761 stats = softd->stats;
762 unit = op->iplo_unit;
763 if (unit == IPL_LOGALL) {
764 for (i = 0; i <= IPL_LOGMAX; i++)
765 stats.ipls_list[i] = softd->dstlist[i];
766 } else if (unit >= 0 && unit <= IPL_LOGMAX) {
767 void *ptr;
768
769 if (op->iplo_name[0] != '\0')
770 ptr = ipf_dstlist_table_find(softd, unit,
771 op->iplo_name);
772 else
773 ptr = softd->dstlist[unit + 1];
774 stats.ipls_list[unit] = ptr;
775 } else {
776 IPFERROR(120024);
777 err = EINVAL;
778 }
779
780 if (err == 0) {
781 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
782 if (err != 0) {
783 IPFERROR(120025);
784 return EFAULT;
785 }
786 }
787 return 0;
788 }
789
790
791 /* ------------------------------------------------------------------------ */
792 /* Function: ipf_dstlist_table_add */
793 /* Returns: int - 0 = success, else error */
794 /* Parameters: softc(I) - pointer to soft context main structure */
795 /* arg(I) - pointer to local context to use */
796 /* op(I) - pointer to lookup operation data */
797 /* */
798 /* Add a new destination table to the list of those available for the given */
799 /* device. Because we seldom operate on these objects (find/add/delete), */
800 /* they are just kept in a simple linked list. */
801 /* ------------------------------------------------------------------------ */
802 static int
ipf_dstlist_table_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)803 ipf_dstlist_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
804 {
805 ipf_dstl_softc_t *softd = arg;
806 ippool_dst_t user, *d, *new;
807 int unit, err;
808
809 d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
810 if (d != NULL) {
811 IPFERROR(120013);
812 return EEXIST;
813 }
814
815 err = COPYIN(op->iplo_struct, &user, sizeof(user));
816 if (err != 0) {
817 IPFERROR(120021);
818 return EFAULT;
819 }
820
821 KMALLOC(new, ippool_dst_t *);
822 if (new == NULL) {
823 softd->stats.ipls_nomem++;
824 IPFERROR(120014);
825 return ENOMEM;
826 }
827 bzero((char *)new, sizeof(*new));
828
829 MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
830
831 strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
832 unit = op->iplo_unit;
833 new->ipld_unit = unit;
834 new->ipld_policy = user.ipld_policy;
835 new->ipld_seed = ipf_random();
836 new->ipld_ref = 1;
837
838 new->ipld_pnext = softd->tails[unit + 1];
839 *softd->tails[unit + 1] = new;
840 softd->tails[unit + 1] = &new->ipld_next;
841 softd->stats.ipls_numlists++;
842
843 return 0;
844 }
845
846
847 /* ------------------------------------------------------------------------ */
848 /* Function: ipf_dstlist_table_del */
849 /* Returns: int - 0 = success, else error */
850 /* Parameters: softc(I) - pointer to soft context main structure */
851 /* arg(I) - pointer to local context to use */
852 /* op(I) - pointer to lookup operation data */
853 /* */
854 /* Find a named destinstion list table and delete it. If there are other */
855 /* references to it, the caller isn't told. */
856 /* ------------------------------------------------------------------------ */
857 static int
ipf_dstlist_table_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)858 ipf_dstlist_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
859 {
860 ippool_dst_t *d;
861
862 d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
863 if (d == NULL) {
864 IPFERROR(120015);
865 return ESRCH;
866 }
867
868 if (d->ipld_dests != NULL) {
869 IPFERROR(120016);
870 return EBUSY;
871 }
872
873 ipf_dstlist_table_remove(softc, arg, d);
874
875 return 0;
876 }
877
878
879 /* ------------------------------------------------------------------------ */
880 /* Function: ipf_dstlist_table_remove */
881 /* Returns: Nil */
882 /* Parameters: softc(I) - pointer to soft context main structure */
883 /* softd(I) - pointer to the destination list context */
884 /* d(I) - pointer to destination list */
885 /* */
886 /* Remove a given destination list from existance. While the IPDST_DELETE */
887 /* flag is set every time we call this function and the reference count is */
888 /* non-zero, the "numdereflists" counter is always incremented because the */
889 /* decision about whether it will be freed or not is not made here. This */
890 /* means that the only action the code can take here is to treat it as if */
891 /* it will become a detached. */
892 /* ------------------------------------------------------------------------ */
893 static void
ipf_dstlist_table_remove(ipf_main_softc_t * softc,ipf_dstl_softc_t * softd,ippool_dst_t * d)894 ipf_dstlist_table_remove(ipf_main_softc_t *softc, ipf_dstl_softc_t *softd,
895 ippool_dst_t *d)
896 {
897
898 if (softd->tails[d->ipld_unit + 1] == &d->ipld_next)
899 softd->tails[d->ipld_unit + 1] = d->ipld_pnext;
900
901 if (d->ipld_pnext != NULL)
902 *d->ipld_pnext = d->ipld_next;
903 if (d->ipld_next != NULL)
904 d->ipld_next->ipld_pnext = d->ipld_pnext;
905 d->ipld_pnext = NULL;
906 d->ipld_next = NULL;
907
908 ipf_dstlist_table_clearnodes(softd, d);
909
910 softd->stats.ipls_numdereflists++;
911 d->ipld_flags |= IPDST_DELETE;
912
913 ipf_dstlist_table_deref(softc, softd, d);
914 }
915
916
917 /* ------------------------------------------------------------------------ */
918 /* Function: ipf_dstlist_table_free */
919 /* Returns: Nil */
920 /* Parameters: softd(I) - pointer to the destination list context */
921 /* d(I) - pointer to destination list */
922 /* */
923 /* Free up a destination list data structure and any other memory that was */
924 /* directly allocated as part of creating it. Individual destination list */
925 /* nodes are not freed. It is assumed the caller will have already emptied */
926 /* the destination list. */
927 /* ------------------------------------------------------------------------ */
928 static void
ipf_dstlist_table_free(ipf_dstl_softc_t * softd,ippool_dst_t * d)929 ipf_dstlist_table_free(ipf_dstl_softc_t *softd, ippool_dst_t *d)
930 {
931 MUTEX_DESTROY(&d->ipld_lock);
932
933 if ((d->ipld_flags & IPDST_DELETE) != 0)
934 softd->stats.ipls_numdereflists--;
935 softd->stats.ipls_numlists--;
936
937 if (d->ipld_dests != NULL) {
938 KFREES(d->ipld_dests,
939 d->ipld_maxnodes * sizeof(*d->ipld_dests));
940 }
941
942 KFREE(d);
943 }
944
945
946 /* ------------------------------------------------------------------------ */
947 /* Function: ipf_dstlist_table_deref */
948 /* Returns: int - 0 = success, else error */
949 /* Parameters: softc(I) - pointer to soft context main structure */
950 /* arg(I) - pointer to local context to use */
951 /* op(I) - pointer to lookup operation data */
952 /* */
953 /* Drops the reference count on a destination list table object and free's */
954 /* it if 0 has been reached. */
955 /* ------------------------------------------------------------------------ */
956 static int
ipf_dstlist_table_deref(ipf_main_softc_t * softc,void * arg,void * table)957 ipf_dstlist_table_deref(ipf_main_softc_t *softc, void *arg, void *table)
958 {
959 ippool_dst_t *d = table;
960
961 d->ipld_ref--;
962 if (d->ipld_ref > 0)
963 return d->ipld_ref;
964
965 ipf_dstlist_table_free(arg, d);
966
967 return 0;
968 }
969
970
971 /* ------------------------------------------------------------------------ */
972 /* Function: ipf_dstlist_table_clearnodes */
973 /* Returns: Nil */
974 /* Parameters: softd(I) - pointer to the destination list context */
975 /* dst(I) - pointer to destination list */
976 /* */
977 /* Free all of the destination nodes attached to the given table. */
978 /* ------------------------------------------------------------------------ */
979 static void
ipf_dstlist_table_clearnodes(ipf_dstl_softc_t * softd,ippool_dst_t * dst)980 ipf_dstlist_table_clearnodes(ipf_dstl_softc_t *softd, ippool_dst_t *dst)
981 {
982 ipf_dstnode_t *node;
983
984 if (dst->ipld_dests == NULL)
985 return;
986
987 while ((node = *dst->ipld_dests) != NULL) {
988 ipf_dstlist_node_free(softd, dst, node);
989 }
990 }
991
992
993 /* ------------------------------------------------------------------------ */
994 /* Function: ipf_dstlist_table_find */
995 /* Returns: int - 0 = success, else error */
996 /* Parameters: arg(I) - pointer to local context to use */
997 /* unit(I) - device we are working with */
998 /* name(I) - destination table name to find */
999 /* */
1000 /* Return a pointer to a destination table that matches the unit+name that */
1001 /* is passed in. */
1002 /* ------------------------------------------------------------------------ */
1003 static void *
ipf_dstlist_table_find(void * arg,int unit,char * name)1004 ipf_dstlist_table_find(void *arg, int unit, char *name)
1005 {
1006 ipf_dstl_softc_t *softd = arg;
1007 ippool_dst_t *d;
1008
1009 for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) {
1010 if ((d->ipld_unit == unit) &&
1011 !strncmp(d->ipld_name, name, FR_GROUPLEN)) {
1012 return d;
1013 }
1014 }
1015
1016 return NULL;
1017 }
1018
1019
1020 /* ------------------------------------------------------------------------ */
1021 /* Function: ipf_dstlist_select_ref */
1022 /* Returns: void * - NULL = failure, else pointer to table */
1023 /* Parameters: arg(I) - pointer to local context to use */
1024 /* unit(I) - device we are working with */
1025 /* name(I) - destination table name to find */
1026 /* */
1027 /* Attempt to find a destination table that matches the name passed in and */
1028 /* if successful, bump up the reference count on it because we intend to */
1029 /* store the pointer to it somewhere else. */
1030 /* ------------------------------------------------------------------------ */
1031 static void *
ipf_dstlist_select_ref(void * arg,int unit,char * name)1032 ipf_dstlist_select_ref(void *arg, int unit, char *name)
1033 {
1034 ippool_dst_t *d;
1035
1036 d = ipf_dstlist_table_find(arg, unit, name);
1037 if (d != NULL) {
1038 MUTEX_ENTER(&d->ipld_lock);
1039 d->ipld_ref++;
1040 MUTEX_EXIT(&d->ipld_lock);
1041 }
1042 return d;
1043 }
1044
1045
1046 /* ------------------------------------------------------------------------ */
1047 /* Function: ipf_dstlist_select */
1048 /* Returns: void * - NULL = failure, else pointer to table */
1049 /* Parameters: fin(I) - pointer to packet information */
1050 /* d(I) - pointer to destination list */
1051 /* */
1052 /* Find the next node in the destination list to be used according to the */
1053 /* defined policy. Of these, "connection" is the most expensive policy to */
1054 /* implement as it always looks for the node with the least number of */
1055 /* connections associated with it. */
1056 /* */
1057 /* The hashes exclude the port numbers so that all protocols map to the */
1058 /* same destination. Otherwise, someone doing a ping would target a */
1059 /* different server than their TCP connection, etc. MD-5 is used to */
1060 /* transform the addressese into something random that the other end could */
1061 /* not easily guess and use in an attack. ipld_seed introduces an unknown */
1062 /* into the hash calculation to increase the difficult of an attacker */
1063 /* guessing the bucket. */
1064 /* */
1065 /* One final comment: mixing different address families in a single pool */
1066 /* will currently result in failures as the address family of the node is */
1067 /* only matched up with that in the packet as the last step. While this can */
1068 /* be coded around for the weighted connection and round-robin models, it */
1069 /* cannot be supported for the hash/random models as they do not search and */
1070 /* nor is the algorithm conducive to searching. */
1071 /* ------------------------------------------------------------------------ */
1072 static ipf_dstnode_t *
ipf_dstlist_select(fr_info_t * fin,ippool_dst_t * d)1073 ipf_dstlist_select(fr_info_t *fin, ippool_dst_t *d)
1074 {
1075 ipf_dstnode_t *node, *sel;
1076 int connects;
1077 union {
1078 u_32_t hash[4];
1079 unsigned char bytes[16];
1080 } h;
1081 MD5_CTX ctx;
1082 int family;
1083 int x;
1084
1085 if (d == NULL || d->ipld_dests == NULL || *d->ipld_dests == NULL)
1086 return NULL;
1087
1088 family = fin->fin_family;
1089
1090 MUTEX_ENTER(&d->ipld_lock);
1091
1092 switch (d->ipld_policy)
1093 {
1094 case IPLDP_ROUNDROBIN:
1095 sel = d->ipld_selected;
1096 if (sel == NULL) {
1097 sel = *d->ipld_dests;
1098 } else {
1099 sel = sel->ipfd_next;
1100 if (sel == NULL)
1101 sel = *d->ipld_dests;
1102 }
1103 break;
1104
1105 case IPLDP_CONNECTION:
1106 if (d->ipld_selected == NULL) {
1107 sel = *d->ipld_dests;
1108 break;
1109 }
1110
1111 sel = d->ipld_selected;
1112 connects = 0x7fffffff;
1113 node = sel->ipfd_next;
1114 if (node == NULL)
1115 node = *d->ipld_dests;
1116 while (node != d->ipld_selected) {
1117 if (node->ipfd_states == 0) {
1118 sel = node;
1119 break;
1120 }
1121 if (node->ipfd_states < connects) {
1122 sel = node;
1123 connects = node->ipfd_states;
1124 }
1125 node = node->ipfd_next;
1126 if (node == NULL)
1127 node = *d->ipld_dests;
1128 }
1129 break;
1130
1131 case IPLDP_RANDOM :
1132 x = ipf_random() % d->ipld_nodes;
1133 sel = d->ipld_dests[x];
1134 break;
1135
1136 case IPLDP_HASHED :
1137 MD5Init(&ctx);
1138 MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
1139 MD5Update(&ctx, (u_char *)&fin->fin_src6,
1140 sizeof(fin->fin_src6));
1141 MD5Update(&ctx, (u_char *)&fin->fin_dst6,
1142 sizeof(fin->fin_dst6));
1143 MD5Final(h.bytes, &ctx);
1144 x = ntohl(h.hash[0]) % d->ipld_nodes;
1145 sel = d->ipld_dests[x];
1146 break;
1147
1148 case IPLDP_SRCHASH :
1149 MD5Init(&ctx);
1150 MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
1151 MD5Update(&ctx, (u_char *)&fin->fin_src6,
1152 sizeof(fin->fin_src6));
1153 MD5Final(h.bytes, &ctx);
1154 x = ntohl(h.hash[0]) % d->ipld_nodes;
1155 sel = d->ipld_dests[x];
1156 break;
1157
1158 case IPLDP_DSTHASH :
1159 MD5Init(&ctx);
1160 MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
1161 MD5Update(&ctx, (u_char *)&fin->fin_dst6,
1162 sizeof(fin->fin_dst6));
1163 MD5Final(h.bytes, &ctx);
1164 x = ntohl(h.hash[0]) % d->ipld_nodes;
1165 sel = d->ipld_dests[x];
1166 break;
1167
1168 default :
1169 sel = NULL;
1170 break;
1171 }
1172
1173 if (sel && sel->ipfd_dest.fd_addr.adf_family != family)
1174 sel = NULL;
1175 d->ipld_selected = sel;
1176
1177 MUTEX_EXIT(&d->ipld_lock);
1178
1179 return sel;
1180 }
1181
1182
1183 /* ------------------------------------------------------------------------ */
1184 /* Function: ipf_dstlist_select_node */
1185 /* Returns: int - -1 == failure, 0 == success */
1186 /* Parameters: fin(I) - pointer to packet information */
1187 /* group(I) - destination pool to search */
1188 /* addr(I) - pointer to store selected address */
1189 /* pfdp(O) - pointer to storage for selected destination node */
1190 /* */
1191 /* This function is only responsible for obtaining the next IP address for */
1192 /* use and storing it in the caller's address space (addr). "addr" is only */
1193 /* used for storage if pfdp is NULL. No permanent reference is currently */
1194 /* kept on the node. */
1195 /* ------------------------------------------------------------------------ */
1196 int
ipf_dstlist_select_node(fr_info_t * fin,void * group,u_32_t * addr,frdest_t * pfdp)1197 ipf_dstlist_select_node(fr_info_t *fin, void *group, u_32_t *addr,
1198 frdest_t *pfdp)
1199 {
1200 #ifdef USE_MUTEXES
1201 ipf_main_softc_t *softc = fin->fin_main_soft;
1202 #endif
1203 ippool_dst_t *d = group;
1204 ipf_dstnode_t *node;
1205 frdest_t *fdp;
1206
1207 READ_ENTER(&softc->ipf_poolrw);
1208
1209 node = ipf_dstlist_select(fin, d);
1210 if (node == NULL) {
1211 RWLOCK_EXIT(&softc->ipf_poolrw);
1212 return -1;
1213 }
1214
1215 if (pfdp != NULL) {
1216 bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp));
1217 } else {
1218 if (fin->fin_family == AF_INET) {
1219 addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
1220 } else if (fin->fin_family == AF_INET6) {
1221 addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
1222 addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1];
1223 addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2];
1224 addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3];
1225 }
1226 }
1227
1228 fdp = &node->ipfd_dest;
1229 if (fdp->fd_ptr == NULL)
1230 fdp->fd_ptr = fin->fin_ifp;
1231
1232 MUTEX_ENTER(&node->ipfd_lock);
1233 node->ipfd_states++;
1234 MUTEX_EXIT(&node->ipfd_lock);
1235
1236 RWLOCK_EXIT(&softc->ipf_poolrw);
1237
1238 return 0;
1239 }
1240
1241
1242 /* ------------------------------------------------------------------------ */
1243 /* Function: ipf_dstlist_expire */
1244 /* Returns: Nil */
1245 /* Parameters: softc(I) - pointer to soft context main structure */
1246 /* arg(I) - pointer to local context to use */
1247 /* */
1248 /* There are currently no objects to expire in destination lists. */
1249 /* ------------------------------------------------------------------------ */
1250 static void
ipf_dstlist_expire(ipf_main_softc_t * softc,void * arg)1251 ipf_dstlist_expire(ipf_main_softc_t *softc, void *arg)
1252 {
1253 return;
1254 }
1255
1256
1257 /* ------------------------------------------------------------------------ */
1258 /* Function: ipf_dstlist_sync */
1259 /* Returns: Nil */
1260 /* Parameters: softc(I) - pointer to soft context main structure */
1261 /* arg(I) - pointer to local context to use */
1262 /* */
1263 /* When a network interface appears or disappears, we need to revalidate */
1264 /* all of the network interface names that have been configured as a target */
1265 /* in a destination list. */
1266 /* ------------------------------------------------------------------------ */
1267 void
ipf_dstlist_sync(ipf_main_softc_t * softc,void * arg)1268 ipf_dstlist_sync(ipf_main_softc_t *softc, void *arg)
1269 {
1270 ipf_dstl_softc_t *softd = arg;
1271 ipf_dstnode_t *node;
1272 ippool_dst_t *list;
1273 int i;
1274 int j;
1275
1276 for (i = 0; i < IPL_LOGMAX; i++) {
1277 for (list = softd->dstlist[i]; list != NULL;
1278 list = list->ipld_next) {
1279 for (j = 0; j < list->ipld_maxnodes; j++) {
1280 node = list->ipld_dests[j];
1281 if (node == NULL)
1282 continue;
1283 if (node->ipfd_dest.fd_name == -1)
1284 continue;
1285 (void) ipf_resolvedest(softc,
1286 node->ipfd_names,
1287 &node->ipfd_dest,
1288 AF_INET);
1289 }
1290 }
1291 }
1292 }
1293