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