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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 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 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 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