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