diff --git a/contrib/ipfilter/ip_dstlist.c b/contrib/ipfilter/ip_dstlist.c deleted file mode 100644 index 2802ef694aa9..000000000000 --- a/contrib/ipfilter/ip_dstlist.c +++ /dev/null @@ -1,1343 +0,0 @@ -/* - * Copyright (C) 2012 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#if defined(KERNEL) || defined(_KERNEL) -# undef KERNEL -# undef _KERNEL -# define KERNEL 1 -# define _KERNEL 1 -#endif -#include -#include -#include -#include -#if !defined(_KERNEL) && !defined(__KERNEL__) -# include -# include -# include -# define _KERNEL -# include -# undef _KERNEL -#else -# include -# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) -# include -# endif -#endif -#include -# include -#include -#if defined(_KERNEL) && !defined(__SVR4) -# include -#endif -#if defined(__SVR4) -# include -# include -# ifdef _KERNEL -# include -# endif -# include -# include -#endif -#if defined(__FreeBSD__) -# include -#endif - -#include -#include - -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_lookup.h" -#include "netinet/ip_dstlist.h" - -/* END OF INCLUDES */ - -#ifdef HAS_SYS_MD5_H -# include -#else -# include "md5.h" -#endif - -#if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $"; -#endif - -typedef struct ipf_dstl_softc_s { - ippool_dst_t *dstlist[LOOKUP_POOL_SZ]; - ippool_dst_t **tails[LOOKUP_POOL_SZ]; - ipf_dstl_stat_t stats; -} ipf_dstl_softc_t; - - -static void *ipf_dstlist_soft_create(ipf_main_softc_t *); -static void ipf_dstlist_soft_destroy(ipf_main_softc_t *, void *); -static int ipf_dstlist_soft_init(ipf_main_softc_t *, void *); -static void ipf_dstlist_soft_fini(ipf_main_softc_t *, void *); -static int ipf_dstlist_addr_find(ipf_main_softc_t *, void *, int, - void *, u_int); -static size_t ipf_dstlist_flush(ipf_main_softc_t *, void *, - iplookupflush_t *); -static int ipf_dstlist_iter_deref(ipf_main_softc_t *, void *, int, int, - void *); -static int ipf_dstlist_iter_next(ipf_main_softc_t *, void *, ipftoken_t *, - ipflookupiter_t *); -static int ipf_dstlist_node_add(ipf_main_softc_t *, void *, - iplookupop_t *, int); -static int ipf_dstlist_node_del(ipf_main_softc_t *, void *, - iplookupop_t *, int); -static int ipf_dstlist_stats_get(ipf_main_softc_t *, void *, - iplookupop_t *); -static int ipf_dstlist_table_add(ipf_main_softc_t *, void *, - iplookupop_t *); -static int ipf_dstlist_table_del(ipf_main_softc_t *, void *, - iplookupop_t *); -static int ipf_dstlist_table_deref(ipf_main_softc_t *, void *, void *); -static void *ipf_dstlist_table_find(void *, int, char *); -static void ipf_dstlist_table_free(ipf_dstl_softc_t *, ippool_dst_t *); -static void ipf_dstlist_table_remove(ipf_main_softc_t *, - ipf_dstl_softc_t *, ippool_dst_t *); -static void ipf_dstlist_table_clearnodes(ipf_dstl_softc_t *, - ippool_dst_t *); -static ipf_dstnode_t *ipf_dstlist_select(fr_info_t *, ippool_dst_t *); -static void *ipf_dstlist_select_ref(void *, int, char *); -static void ipf_dstlist_node_free(ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *); -static int ipf_dstlist_node_deref(void *, ipf_dstnode_t *); -static void ipf_dstlist_expire(ipf_main_softc_t *, void *); -static void ipf_dstlist_sync(ipf_main_softc_t *, void *); - -ipf_lookup_t ipf_dstlist_backend = { - IPLT_DSTLIST, - ipf_dstlist_soft_create, - ipf_dstlist_soft_destroy, - ipf_dstlist_soft_init, - ipf_dstlist_soft_fini, - ipf_dstlist_addr_find, - ipf_dstlist_flush, - ipf_dstlist_iter_deref, - ipf_dstlist_iter_next, - ipf_dstlist_node_add, - ipf_dstlist_node_del, - ipf_dstlist_stats_get, - ipf_dstlist_table_add, - ipf_dstlist_table_del, - ipf_dstlist_table_deref, - ipf_dstlist_table_find, - ipf_dstlist_select_ref, - ipf_dstlist_select_node, - ipf_dstlist_expire, - ipf_dstlist_sync -}; - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_soft_create */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* */ -/* Allocating a chunk of memory filled with 0's is enough for the current */ -/* soft context used with destination lists. */ -/* ------------------------------------------------------------------------ */ -static void * -ipf_dstlist_soft_create(softc) - ipf_main_softc_t *softc; -{ - ipf_dstl_softc_t *softd; - int i; - - KMALLOC(softd, ipf_dstl_softc_t *); - if (softd == NULL) { - IPFERROR(120028); - return NULL; - } - - bzero((char *)softd, sizeof(*softd)); - for (i = 0; i <= IPL_LOGMAX; i++) - softd->tails[i] = &softd->dstlist[i]; - - return softd; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_soft_destroy */ -/* Returns: Nil */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* */ -/* For destination lists, the only thing we have to do when destroying the */ -/* soft context is free it! */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_soft_destroy(softc, arg) - ipf_main_softc_t *softc; - void *arg; -{ - ipf_dstl_softc_t *softd = arg; - - KFREE(softd); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_soft_init */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* */ -/* There is currently no soft context for destination list management. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_soft_init(softc, arg) - ipf_main_softc_t *softc; - void *arg; -{ - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_soft_fini */ -/* Returns: Nil */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* */ -/* There is currently no soft context for destination list management. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_soft_fini(softc, arg) - ipf_main_softc_t *softc; - void *arg; -{ - ipf_dstl_softc_t *softd = arg; - int i; - - for (i = -1; i <= IPL_LOGMAX; i++) { - while (softd->dstlist[i + 1] != NULL) { - ipf_dstlist_table_remove(softc, softd, - softd->dstlist[i + 1]); - } - } - - ASSERT(softd->stats.ipls_numderefnodes == 0); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_addr_find */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg1(I) - pointer to local context to use */ -/* arg2(I) - pointer to local context to use */ -/* arg3(I) - pointer to local context to use */ -/* arg4(I) - pointer to local context to use */ -/* */ -/* There is currently no such thing as searching a destination list for an */ -/* address so this function becomes a no-op. Its presence is required as */ -/* ipf_lookup_res_name() stores the "addr_find" function pointer in the */ -/* pointer passed in to it as funcptr, although it could be a generic null- */ -/* op function rather than a specific one. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int -ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4) - ipf_main_softc_t *softc; - void *arg1, *arg3; - int arg2; - u_int arg4; -{ - return -1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_flush */ -/* Returns: int - number of objects deleted */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* fop(I) - pointer to lookup flush operation data */ -/* */ -/* Flush all of the destination tables that match the data passed in with */ -/* the iplookupflush_t. There are two ways to match objects: the device for */ -/* which they are to be used with and their name. */ -/* ------------------------------------------------------------------------ */ -static size_t -ipf_dstlist_flush(softc, arg, fop) - ipf_main_softc_t *softc; - void *arg; - iplookupflush_t *fop; -{ - ipf_dstl_softc_t *softd = arg; - ippool_dst_t *node, *next; - int n, i; - - for (n = 0, i = -1; i <= IPL_LOGMAX; i++) { - if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i) - continue; - for (node = softd->dstlist[i + 1]; node != NULL; node = next) { - next = node->ipld_next; - - if ((*fop->iplf_name != '\0') && - strncmp(fop->iplf_name, node->ipld_name, - FR_GROUPLEN)) - continue; - - ipf_dstlist_table_remove(softc, softd, node); - n++; - } - } - return n; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_iter_deref */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* otype(I) - type of data structure to iterate through */ -/* unit(I) - device we are working with */ -/* data(I) - address of object in kernel space */ -/* */ -/* This function is called when the iteration token is being free'd and is */ -/* responsible for dropping the reference count of the structure it points */ -/* to. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_iter_deref(softc, arg, otype, unit, data) - ipf_main_softc_t *softc; - void *arg; - int otype, unit; - void *data; -{ - if (data == NULL) { - IPFERROR(120001); - return EINVAL; - } - - if (unit < -1 || unit > IPL_LOGMAX) { - IPFERROR(120002); - return EINVAL; - } - - switch (otype) - { - case IPFLOOKUPITER_LIST : - ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data); - break; - - case IPFLOOKUPITER_NODE : - ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data); - break; - } - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_iter_next */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* uid(I) - uid of process doing the ioctl */ -/* */ -/* This function is responsible for either selecting the next destination */ -/* list or node on a destination list to be returned as a user process */ -/* iterates through the list of destination lists or nodes. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_iter_next(softc, arg, token, iter) - ipf_main_softc_t *softc; - void *arg; - ipftoken_t *token; - ipflookupiter_t *iter; -{ - ipf_dstnode_t zn, *nextnode = NULL, *node = NULL; - ippool_dst_t zero, *next = NULL, *dsttab = NULL; - ipf_dstl_softc_t *softd = arg; - int err = 0; - void *hint; - - switch (iter->ili_otype) - { - case IPFLOOKUPITER_LIST : - dsttab = token->ipt_data; - if (dsttab == NULL) { - next = softd->dstlist[(int)iter->ili_unit + 1]; - } else { - next = dsttab->ipld_next; - } - - if (next != NULL) { - ATOMIC_INC32(next->ipld_ref); - token->ipt_data = next; - hint = next->ipld_next; - } else { - bzero((char *)&zero, sizeof(zero)); - next = &zero; - token->ipt_data = NULL; - hint = NULL; - } - break; - - case IPFLOOKUPITER_NODE : - node = token->ipt_data; - if (node == NULL) { - dsttab = ipf_dstlist_table_find(arg, iter->ili_unit, - iter->ili_name); - if (dsttab == NULL) { - IPFERROR(120004); - err = ESRCH; - nextnode = NULL; - } else { - if (dsttab->ipld_dests == NULL) - nextnode = NULL; - else - nextnode = *dsttab->ipld_dests; - dsttab = NULL; - } - } else { - nextnode = node->ipfd_next; - } - - if (nextnode != NULL) { - MUTEX_ENTER(&nextnode->ipfd_lock); - nextnode->ipfd_ref++; - MUTEX_EXIT(&nextnode->ipfd_lock); - token->ipt_data = nextnode; - hint = nextnode->ipfd_next; - } else { - bzero((char *)&zn, sizeof(zn)); - nextnode = &zn; - token->ipt_data = NULL; - hint = NULL; - } - break; - default : - IPFERROR(120003); - err = EINVAL; - break; - } - - if (err != 0) - return err; - - switch (iter->ili_otype) - { - case IPFLOOKUPITER_LIST : - if (dsttab != NULL) - ipf_dstlist_table_deref(softc, arg, dsttab); - err = COPYOUT(next, iter->ili_data, sizeof(*next)); - if (err != 0) { - IPFERROR(120005); - err = EFAULT; - } - break; - - case IPFLOOKUPITER_NODE : - if (node != NULL) - ipf_dstlist_node_deref(arg, node); - err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode)); - if (err != 0) { - IPFERROR(120006); - err = EFAULT; - } - break; - } - - if (hint == NULL) - ipf_token_mark_complete(token); - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_node_add */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* uid(I) - uid of process doing the ioctl */ -/* Locks: WRITE(ipf_poolrw) */ -/* */ -/* Add a new node to a destination list. To do this, we only copy in the */ -/* frdest_t structure because that contains the only data required from the */ -/* application to create a new node. The frdest_t doesn't contain the name */ -/* itself. When loading filter rules, fd_name is a 'pointer' to the name. */ -/* In this case, the 'pointer' does not work, instead it is the length of */ -/* the name and the name is immediately following the frdest_t structure. */ -/* fd_name must include the trailing \0, so it should be strlen(str) + 1. */ -/* For simple sanity checking, an upper bound on the size of fd_name is */ -/* imposed - 128. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_node_add(softc, arg, op, uid) - ipf_main_softc_t *softc; - void *arg; - iplookupop_t *op; - int uid; -{ - ipf_dstl_softc_t *softd = arg; - ipf_dstnode_t *node, **nodes; - ippool_dst_t *d; - frdest_t dest; - int err; - - if (op->iplo_size < sizeof(frdest_t)) { - IPFERROR(120007); - return EINVAL; - } - - err = COPYIN(op->iplo_struct, &dest, sizeof(dest)); - if (err != 0) { - IPFERROR(120009); - return EFAULT; - } - - d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); - if (d == NULL) { - IPFERROR(120010); - return ESRCH; - } - - switch (dest.fd_addr.adf_family) - { - case AF_INET : - case AF_INET6 : - break; - default : - IPFERROR(120019); - return EINVAL; - } - - if (dest.fd_name < -1 || dest.fd_name > 128) { - IPFERROR(120018); - return EINVAL; - } - - KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name); - if (node == NULL) { - softd->stats.ipls_nomem++; - IPFERROR(120008); - return ENOMEM; - } - bzero((char *)node, sizeof(*node) + dest.fd_name); - - bcopy(&dest, &node->ipfd_dest, sizeof(dest)); - node->ipfd_size = sizeof(*node) + dest.fd_name; - - if (dest.fd_name > 0) { - /* - * fd_name starts out as the length of the string to copy - * in (including \0) and ends up being the offset from - * fd_names (0). - */ - err = COPYIN((char *)op->iplo_struct + sizeof(dest), - node->ipfd_names, dest.fd_name); - if (err != 0) { - IPFERROR(120017); - KFREES(node, node->ipfd_size); - return EFAULT; - } - node->ipfd_dest.fd_name = 0; - } else { - node->ipfd_dest.fd_name = -1; - } - - if (d->ipld_nodes == d->ipld_maxnodes) { - KMALLOCS(nodes, ipf_dstnode_t **, - sizeof(*nodes) * (d->ipld_maxnodes + 1)); - if (nodes == NULL) { - softd->stats.ipls_nomem++; - IPFERROR(120022); - KFREES(node, node->ipfd_size); - return ENOMEM; - } - if (d->ipld_dests != NULL) { - bcopy(d->ipld_dests, nodes, - sizeof(*nodes) * d->ipld_maxnodes); - KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes); - nodes[0]->ipfd_pnext = nodes; - } - d->ipld_dests = nodes; - d->ipld_maxnodes++; - } - d->ipld_dests[d->ipld_nodes] = node; - d->ipld_nodes++; - - if (d->ipld_nodes == 1) { - node->ipfd_pnext = d->ipld_dests; - } else if (d->ipld_nodes > 1) { - node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next; - } - *node->ipfd_pnext = node; - - MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock"); - node->ipfd_uid = uid; - node->ipfd_ref = 1; - if (node->ipfd_dest.fd_name == 0) - (void) ipf_resolvedest(softc, node->ipfd_names, - &node->ipfd_dest, AF_INET); -#ifdef USE_INET6 - if (node->ipfd_dest.fd_name == 0 && - node->ipfd_dest.fd_ptr == (void *)-1) - (void) ipf_resolvedest(softc, node->ipfd_names, - &node->ipfd_dest, AF_INET6); -#endif - - softd->stats.ipls_numnodes++; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_node_deref */ -/* Returns: int - 0 = success, else error */ -/* Parameters: arg(I) - pointer to local context to use */ -/* node(I) - pointer to destionation node to free */ -/* */ -/* Dereference the use count by one. If it drops to zero then we can assume */ -/* that it has been removed from any lists/tables and is ripe for freeing. */ -/* The pointer to context is required for the purpose of maintaining */ -/* statistics. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_node_deref(arg, node) - void *arg; - ipf_dstnode_t *node; -{ - ipf_dstl_softc_t *softd = arg; - int ref; - - MUTEX_ENTER(&node->ipfd_lock); - ref = --node->ipfd_ref; - MUTEX_EXIT(&node->ipfd_lock); - - if (ref > 0) - return 0; - - if ((node->ipfd_flags & IPDST_DELETE) != 0) - softd->stats.ipls_numderefnodes--; - MUTEX_DESTROY(&node->ipfd_lock); - KFREES(node, node->ipfd_size); - softd->stats.ipls_numnodes--; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_node_del */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* uid(I) - uid of process doing the ioctl */ -/* */ -/* Look for a matching destination node on the named table and free it if */ -/* found. Because the name embedded in the frdest_t is variable in length, */ -/* it is necessary to allocate some memory locally, to complete this op. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_node_del(softc, arg, op, uid) - ipf_main_softc_t *softc; - void *arg; - iplookupop_t *op; - int uid; -{ - ipf_dstl_softc_t *softd = arg; - ipf_dstnode_t *node; - frdest_t frd, *temp; - ippool_dst_t *d; - size_t size; - int err; - - d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); - if (d == NULL) { - IPFERROR(120012); - return ESRCH; - } - - err = COPYIN(op->iplo_struct, &frd, sizeof(frd)); - if (err != 0) { - IPFERROR(120011); - return EFAULT; - } - - size = sizeof(*temp) + frd.fd_name; - KMALLOCS(temp, frdest_t *, size); - if (temp == NULL) { - softd->stats.ipls_nomem++; - IPFERROR(120026); - return ENOMEM; - } - - err = COPYIN(op->iplo_struct, temp, size); - if (err != 0) { - IPFERROR(120027); - return EFAULT; - } - - MUTEX_ENTER(&d->ipld_lock); - for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) { - if ((uid != 0) && (node->ipfd_uid != uid)) - continue; - if (node->ipfd_size != size) - continue; - if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6, - size - offsetof(frdest_t, fd_ip6))) { - ipf_dstlist_node_free(softd, d, node); - MUTEX_EXIT(&d->ipld_lock); - KFREES(temp, size); - return 0; - } - } - MUTEX_EXIT(&d->ipld_lock); - KFREES(temp, size); - - return ESRCH; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_node_free */ -/* Returns: Nil */ -/* Parameters: softd(I) - pointer to the destination list context */ -/* d(I) - pointer to destination list */ -/* node(I) - pointer to node to free */ -/* Locks: MUTEX(ipld_lock) or WRITE(ipf_poolrw) */ -/* */ -/* Free the destination node by first removing it from any lists and then */ -/* checking if this was the last reference held to the object. While the */ -/* array of pointers to nodes is compacted, its size isn't reduced (by way */ -/* of allocating a new smaller one and copying) because the belief is that */ -/* it is likely the array will again reach that size. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_node_free(softd, d, node) - ipf_dstl_softc_t *softd; - ippool_dst_t *d; - ipf_dstnode_t *node; -{ - int i; - - /* - * Compact the array of pointers to nodes. - */ - for (i = 0; i < d->ipld_nodes; i++) - if (d->ipld_dests[i] == node) - break; - if (d->ipld_nodes - i > 1) { - bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i], - sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1)); - } - d->ipld_nodes--; - - if (node->ipfd_pnext != NULL) - *node->ipfd_pnext = node->ipfd_next; - if (node->ipfd_next != NULL) - node->ipfd_next->ipfd_pnext = node->ipfd_pnext; - node->ipfd_pnext = NULL; - node->ipfd_next = NULL; - - if ((node->ipfd_flags & IPDST_DELETE) == 0) { - softd->stats.ipls_numderefnodes++; - node->ipfd_flags |= IPDST_DELETE; - } - - ipf_dstlist_node_deref(softd, node); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_stats_get */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* */ -/* Return the current statistics for destination lists. This may be for all */ -/* of them or just information pertaining to a particular table. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int -ipf_dstlist_stats_get(softc, arg, op) - ipf_main_softc_t *softc; - void *arg; - iplookupop_t *op; -{ - ipf_dstl_softc_t *softd = arg; - ipf_dstl_stat_t stats; - int unit, i, err = 0; - - if (op->iplo_size != sizeof(ipf_dstl_stat_t)) { - IPFERROR(120023); - return EINVAL; - } - - stats = softd->stats; - unit = op->iplo_unit; - if (unit == IPL_LOGALL) { - for (i = 0; i <= IPL_LOGMAX; i++) - stats.ipls_list[i] = softd->dstlist[i]; - } else if (unit >= 0 && unit <= IPL_LOGMAX) { - void *ptr; - - if (op->iplo_name[0] != '\0') - ptr = ipf_dstlist_table_find(softd, unit, - op->iplo_name); - else - ptr = softd->dstlist[unit + 1]; - stats.ipls_list[unit] = ptr; - } else { - IPFERROR(120024); - err = EINVAL; - } - - if (err == 0) { - err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); - if (err != 0) { - IPFERROR(120025); - return EFAULT; - } - } - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_add */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* */ -/* Add a new destination table to the list of those available for the given */ -/* device. Because we seldom operate on these objects (find/add/delete), */ -/* they are just kept in a simple linked list. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_table_add(softc, arg, op) - ipf_main_softc_t *softc; - void *arg; - iplookupop_t *op; -{ - ipf_dstl_softc_t *softd = arg; - ippool_dst_t user, *d, *new; - int unit, err; - - d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); - if (d != NULL) { - IPFERROR(120013); - return EEXIST; - } - - err = COPYIN(op->iplo_struct, &user, sizeof(user)); - if (err != 0) { - IPFERROR(120021); - return EFAULT; - } - - KMALLOC(new, ippool_dst_t *); - if (new == NULL) { - softd->stats.ipls_nomem++; - IPFERROR(120014); - return ENOMEM; - } - bzero((char *)new, sizeof(*new)); - - MUTEX_INIT(&new->ipld_lock, "ipf dst table lock"); - - strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN); - unit = op->iplo_unit; - new->ipld_unit = unit; - new->ipld_policy = user.ipld_policy; - new->ipld_seed = ipf_random(); - new->ipld_ref = 1; - - new->ipld_pnext = softd->tails[unit + 1]; - *softd->tails[unit + 1] = new; - softd->tails[unit + 1] = &new->ipld_next; - softd->stats.ipls_numlists++; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_del */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* */ -/* Find a named destinstion list table and delete it. If there are other */ -/* references to it, the caller isn't told. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_table_del(softc, arg, op) - ipf_main_softc_t *softc; - void *arg; - iplookupop_t *op; -{ - ippool_dst_t *d; - - d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); - if (d == NULL) { - IPFERROR(120015); - return ESRCH; - } - - if (d->ipld_dests != NULL) { - IPFERROR(120016); - return EBUSY; - } - - ipf_dstlist_table_remove(softc, arg, d); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_remove */ -/* Returns: Nil */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* softd(I) - pointer to the destination list context */ -/* d(I) - pointer to destination list */ -/* */ -/* Remove a given destination list from existance. While the IPDST_DELETE */ -/* flag is set every time we call this function and the reference count is */ -/* non-zero, the "numdereflists" counter is always incremented because the */ -/* decision about whether it will be freed or not is not made here. This */ -/* means that the only action the code can take here is to treat it as if */ -/* it will become a detached. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_table_remove(softc, softd, d) - ipf_main_softc_t *softc; - ipf_dstl_softc_t *softd; - ippool_dst_t *d; -{ - - if (softd->tails[d->ipld_unit + 1] == &d->ipld_next) - softd->tails[d->ipld_unit + 1] = d->ipld_pnext; - - if (d->ipld_pnext != NULL) - *d->ipld_pnext = d->ipld_next; - if (d->ipld_next != NULL) - d->ipld_next->ipld_pnext = d->ipld_pnext; - d->ipld_pnext = NULL; - d->ipld_next = NULL; - - ipf_dstlist_table_clearnodes(softd, d); - - softd->stats.ipls_numdereflists++; - d->ipld_flags |= IPDST_DELETE; - - ipf_dstlist_table_deref(softc, softd, d); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_free */ -/* Returns: Nil */ -/* Parameters: softd(I) - pointer to the destination list context */ -/* d(I) - pointer to destination list */ -/* */ -/* Free up a destination list data structure and any other memory that was */ -/* directly allocated as part of creating it. Individual destination list */ -/* nodes are not freed. It is assumed the caller will have already emptied */ -/* the destination list. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_table_free(softd, d) - ipf_dstl_softc_t *softd; - ippool_dst_t *d; -{ - MUTEX_DESTROY(&d->ipld_lock); - - if ((d->ipld_flags & IPDST_DELETE) != 0) - softd->stats.ipls_numdereflists--; - softd->stats.ipls_numlists--; - - if (d->ipld_dests != NULL) { - KFREES(d->ipld_dests, - d->ipld_maxnodes * sizeof(*d->ipld_dests)); - } - - KFREE(d); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_deref */ -/* Returns: int - 0 = success, else error */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* op(I) - pointer to lookup operation data */ -/* */ -/* Drops the reference count on a destination list table object and free's */ -/* it if 0 has been reached. */ -/* ------------------------------------------------------------------------ */ -static int -ipf_dstlist_table_deref(softc, arg, table) - ipf_main_softc_t *softc; - void *arg; - void *table; -{ - ippool_dst_t *d = table; - - d->ipld_ref--; - if (d->ipld_ref > 0) - return d->ipld_ref; - - ipf_dstlist_table_free(arg, d); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_clearnodes */ -/* Returns: Nil */ -/* Parameters: softd(I) - pointer to the destination list context */ -/* dst(I) - pointer to destination list */ -/* */ -/* Free all of the destination nodes attached to the given table. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_table_clearnodes(softd, dst) - ipf_dstl_softc_t *softd; - ippool_dst_t *dst; -{ - ipf_dstnode_t *node; - - if (dst->ipld_dests == NULL) - return; - - while ((node = *dst->ipld_dests) != NULL) { - ipf_dstlist_node_free(softd, dst, node); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_table_find */ -/* Returns: int - 0 = success, else error */ -/* Parameters: arg(I) - pointer to local context to use */ -/* unit(I) - device we are working with */ -/* name(I) - destination table name to find */ -/* */ -/* Return a pointer to a destination table that matches the unit+name that */ -/* is passed in. */ -/* ------------------------------------------------------------------------ */ -static void * -ipf_dstlist_table_find(arg, unit, name) - void *arg; - int unit; - char *name; -{ - ipf_dstl_softc_t *softd = arg; - ippool_dst_t *d; - - for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) { - if ((d->ipld_unit == unit) && - !strncmp(d->ipld_name, name, FR_GROUPLEN)) { - return d; - } - } - - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_select_ref */ -/* Returns: void * - NULL = failure, else pointer to table */ -/* Parameters: arg(I) - pointer to local context to use */ -/* unit(I) - device we are working with */ -/* name(I) - destination table name to find */ -/* */ -/* Attempt to find a destination table that matches the name passed in and */ -/* if successful, bump up the reference count on it because we intend to */ -/* store the pointer to it somewhere else. */ -/* ------------------------------------------------------------------------ */ -static void * -ipf_dstlist_select_ref(arg, unit, name) - void *arg; - int unit; - char *name; -{ - ippool_dst_t *d; - - d = ipf_dstlist_table_find(arg, unit, name); - if (d != NULL) { - MUTEX_ENTER(&d->ipld_lock); - d->ipld_ref++; - MUTEX_EXIT(&d->ipld_lock); - } - return d; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_select */ -/* Returns: void * - NULL = failure, else pointer to table */ -/* Parameters: fin(I) - pointer to packet information */ -/* d(I) - pointer to destination list */ -/* */ -/* Find the next node in the destination list to be used according to the */ -/* defined policy. Of these, "connection" is the most expensive policy to */ -/* implement as it always looks for the node with the least number of */ -/* connections associated with it. */ -/* */ -/* The hashes exclude the port numbers so that all protocols map to the */ -/* same destination. Otherwise, someone doing a ping would target a */ -/* different server than their TCP connection, etc. MD-5 is used to */ -/* transform the addressese into something random that the other end could */ -/* not easily guess and use in an attack. ipld_seed introduces an unknown */ -/* into the hash calculation to increase the difficult of an attacker */ -/* guessing the bucket. */ -/* */ -/* One final comment: mixing different address families in a single pool */ -/* will currently result in failures as the address family of the node is */ -/* only matched up with that in the packet as the last step. While this can */ -/* be coded around for the weighted connection and round-robin models, it */ -/* cannot be supported for the hash/random models as they do not search and */ -/* nor is the algorithm conducive to searching. */ -/* ------------------------------------------------------------------------ */ -static ipf_dstnode_t * -ipf_dstlist_select(fin, d) - fr_info_t *fin; - ippool_dst_t *d; -{ - ipf_dstnode_t *node, *sel; - int connects; - u_32_t hash[4]; - MD5_CTX ctx; - int family; - int x; - - if (d->ipld_dests == NULL || *d->ipld_dests == NULL) - return NULL; - - family = fin->fin_family; - - MUTEX_ENTER(&d->ipld_lock); - - switch (d->ipld_policy) - { - case IPLDP_ROUNDROBIN: - sel = d->ipld_selected; - if (sel == NULL) { - sel = *d->ipld_dests; - } else { - sel = sel->ipfd_next; - if (sel == NULL) - sel = *d->ipld_dests; - } - break; - - case IPLDP_CONNECTION: - if (d->ipld_selected == NULL) { - sel = *d->ipld_dests; - break; - } - - sel = d->ipld_selected; - connects = 0x7fffffff; - node = sel->ipfd_next; - if (node == NULL) - node = *d->ipld_dests; - while (node != d->ipld_selected) { - if (node->ipfd_states == 0) { - sel = node; - break; - } - if (node->ipfd_states < connects) { - sel = node; - connects = node->ipfd_states; - } - node = node->ipfd_next; - if (node == NULL) - node = *d->ipld_dests; - } - break; - - case IPLDP_RANDOM : - x = ipf_random() % d->ipld_nodes; - sel = d->ipld_dests[x]; - break; - - case IPLDP_HASHED : - MD5Init(&ctx); - MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); - MD5Update(&ctx, (u_char *)&fin->fin_src6, - sizeof(fin->fin_src6)); - MD5Update(&ctx, (u_char *)&fin->fin_dst6, - sizeof(fin->fin_dst6)); - MD5Final((u_char *)hash, &ctx); - x = hash[0] % d->ipld_nodes; - sel = d->ipld_dests[x]; - break; - - case IPLDP_SRCHASH : - MD5Init(&ctx); - MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); - MD5Update(&ctx, (u_char *)&fin->fin_src6, - sizeof(fin->fin_src6)); - MD5Final((u_char *)hash, &ctx); - x = hash[0] % d->ipld_nodes; - sel = d->ipld_dests[x]; - break; - - case IPLDP_DSTHASH : - MD5Init(&ctx); - MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); - MD5Update(&ctx, (u_char *)&fin->fin_dst6, - sizeof(fin->fin_dst6)); - MD5Final((u_char *)hash, &ctx); - x = hash[0] % d->ipld_nodes; - sel = d->ipld_dests[x]; - break; - - default : - sel = NULL; - break; - } - - if (sel->ipfd_dest.fd_addr.adf_family != family) - sel = NULL; - d->ipld_selected = sel; - - MUTEX_EXIT(&d->ipld_lock); - - return sel; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_select_node */ -/* Returns: int - -1 == failure, 0 == success */ -/* Parameters: fin(I) - pointer to packet information */ -/* group(I) - destination pool to search */ -/* addr(I) - pointer to store selected address */ -/* pfdp(O) - pointer to storage for selected destination node */ -/* */ -/* This function is only responsible for obtaining the next IP address for */ -/* use and storing it in the caller's address space (addr). "addr" is only */ -/* used for storage if pfdp is NULL. No permanent reference is currently */ -/* kept on the node. */ -/* ------------------------------------------------------------------------ */ -int -ipf_dstlist_select_node(fin, group, addr, pfdp) - fr_info_t *fin; - void *group; - u_32_t *addr; - frdest_t *pfdp; -{ -#ifdef USE_MUTEXES - ipf_main_softc_t *softc = fin->fin_main_soft; -#endif - ippool_dst_t *d = group; - ipf_dstnode_t *node; - frdest_t *fdp; - - READ_ENTER(&softc->ipf_poolrw); - - node = ipf_dstlist_select(fin, d); - if (node == NULL) { - RWLOCK_EXIT(&softc->ipf_poolrw); - return -1; - } - - if (pfdp != NULL) { - bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp)); - } else { - if (fin->fin_family == AF_INET) { - addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0]; - } else if (fin->fin_family == AF_INET6) { - addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0]; - addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1]; - addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2]; - addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3]; - } - } - - fdp = &node->ipfd_dest; - if (fdp->fd_ptr == NULL) - fdp->fd_ptr = fin->fin_ifp; - - MUTEX_ENTER(&node->ipfd_lock); - node->ipfd_states++; - MUTEX_EXIT(&node->ipfd_lock); - - RWLOCK_EXIT(&softc->ipf_poolrw); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_expire */ -/* Returns: Nil */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* */ -/* There are currently no objects to expire in destination lists. */ -/* ------------------------------------------------------------------------ */ -static void -ipf_dstlist_expire(softc, arg) - ipf_main_softc_t *softc; - void *arg; -{ - return; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_dstlist_sync */ -/* Returns: Nil */ -/* Parameters: softc(I) - pointer to soft context main structure */ -/* arg(I) - pointer to local context to use */ -/* */ -/* When a network interface appears or disappears, we need to revalidate */ -/* all of the network interface names that have been configured as a target */ -/* in a destination list. */ -/* ------------------------------------------------------------------------ */ -void -ipf_dstlist_sync(softc, arg) - ipf_main_softc_t *softc; - void *arg; -{ - ipf_dstl_softc_t *softd = arg; - ipf_dstnode_t *node; - ippool_dst_t *list; - int i; - int j; - - for (i = 0; i < IPL_LOGMAX; i++) { - for (list = softd->dstlist[i]; list != NULL; - list = list->ipld_next) { - for (j = 0; j < list->ipld_maxnodes; j++) { - node = list->ipld_dests[j]; - if (node == NULL) - continue; - if (node->ipfd_dest.fd_name == -1) - continue; - (void) ipf_resolvedest(softc, - node->ipfd_names, - &node->ipfd_dest, - AF_INET); - } - } - } -} diff --git a/contrib/ipfilter/ip_dstlist.h b/contrib/ipfilter/ip_dstlist.h deleted file mode 100644 index c4acd78dfd94..000000000000 --- a/contrib/ipfilter/ip_dstlist.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * $Id: ip_dstlist.h,v 1.5.2.6 2012/07/22 08:04:23 darren_r Exp $ - */ - -#ifndef __IP_DSTLIST_H__ -#define __IP_DSTLIST_H__ - -typedef struct ipf_dstnode { - struct ipf_dstnode *ipfd_next; - struct ipf_dstnode **ipfd_pnext; - ipfmutex_t ipfd_lock; - frdest_t ipfd_dest; - u_long ipfd_syncat; - int ipfd_flags; - int ipfd_size; - int ipfd_states; - int ipfd_ref; - int ipfd_uid; - char ipfd_names[1]; -} ipf_dstnode_t; - -typedef enum ippool_policy_e { - IPLDP_NONE = 0, - IPLDP_ROUNDROBIN, - IPLDP_CONNECTION, - IPLDP_RANDOM, - IPLDP_HASHED, - IPLDP_SRCHASH, - IPLDP_DSTHASH -} ippool_policy_t; - -typedef struct ippool_dst { - struct ippool_dst *ipld_next; - struct ippool_dst **ipld_pnext; - ipfmutex_t ipld_lock; - int ipld_seed; - int ipld_unit; - int ipld_ref; - int ipld_flags; - int ipld_nodes; - int ipld_maxnodes; - ippool_policy_t ipld_policy; - ipf_dstnode_t **ipld_dests; - ipf_dstnode_t *ipld_selected; - char ipld_name[FR_GROUPLEN]; -} ippool_dst_t; - -#define IPDST_DELETE 0x01 - -typedef struct dstlist_stat_s { - void *ipls_list[LOOKUP_POOL_SZ]; - int ipls_numlists; - u_long ipls_nomem; - int ipls_numnodes; - int ipls_numdereflists; - int ipls_numderefnodes; -} ipf_dstl_stat_t; - -extern ipf_lookup_t ipf_dstlist_backend; - -extern int ipf_dstlist_select_node(fr_info_t *, void *, u_32_t *, - frdest_t *); - -#endif /* __IP_DSTLIST_H__ */