diff options
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_lookup.c')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_lookup.c | 935 |
1 files changed, 622 insertions, 313 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.c b/sys/contrib/ipfilter/netinet/ip_lookup.c index e33a6fe..45999e0 100644 --- a/sys/contrib/ipfilter/netinet/ip_lookup.c +++ b/sys/contrib/ipfilter/netinet/ip_lookup.c @@ -1,5 +1,6 @@ +/* $FreeBSD$ */ /* - * Copyright (C) 2002-2003 by Darren Reed. + * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ @@ -24,7 +25,9 @@ # include <sys/ioctl.h> #endif #if !defined(_KERNEL) +# include <stdio.h> # include <string.h> +# include <stdlib.h> # define _KERNEL # ifdef __OpenBSD__ struct file; @@ -33,106 +36,223 @@ struct file; # undef _KERNEL #endif #include <sys/socket.h> -#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL) -# include "radix_ipf_local.h" -# define _RADIX_H_ -#endif #include <net/if.h> #if defined(__FreeBSD__) -# include <sys/cdefs.h> -# include <sys/proc.h> +# include <sys/cdefs.h> +# include <sys/proc.h> #endif #if defined(_KERNEL) # include <sys/systm.h> # if !defined(__SVR4) && !defined(__svr4__) # include <sys/mbuf.h> # endif +#else +# include "ipf.h" #endif #include <netinet/in.h> #include "netinet/ip_compat.h" #include "netinet/ip_fil.h" +#include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" -#include "netinet/ip_lookup.h" +#include "netinet/ip_dstlist.h" /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.19 2007/10/11 09:05:51 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id$"; #endif -#ifdef IPFILTER_LOOKUP -int ip_lookup_inited = 0; +/* + * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the + * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number + * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not + * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond + * to the minor device number for their respective device. Thus where there is + * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to + * [0.POOL_LOOKUP_MAX]. + */ +static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int)); +static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int)); +static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t)); +static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t)); +static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t)); +static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t)); +static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *)); +static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *)); + +#define MAX_BACKENDS 3 +static ipf_lookup_t *backends[MAX_BACKENDS] = { + &ipf_pool_backend, + &ipf_htable_backend, + &ipf_dstlist_backend +}; + -static int iplookup_addnode __P((caddr_t)); -static int iplookup_delnode __P((caddr_t data)); -static int iplookup_addtable __P((caddr_t)); -static int iplookup_deltable __P((caddr_t)); -static int iplookup_stats __P((caddr_t)); -static int iplookup_flush __P((caddr_t)); -static int iplookup_iterate __P((void *, int, void *)); -static int iplookup_deltok __P((void *, int, void *)); +typedef struct ipf_lookup_softc_s { + void *ipf_back[MAX_BACKENDS]; +} ipf_lookup_softc_t; /* ------------------------------------------------------------------------ */ -/* Function: iplookup_init */ -/* Returns: int - 0 = success, else error */ -/* Parameters: Nil */ +/* Function: ipf_lookup_init */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ /* */ /* Initialise all of the subcomponents of the lookup infrstructure. */ /* ------------------------------------------------------------------------ */ -int ip_lookup_init() +void * +ipf_lookup_soft_create(softc) + ipf_main_softc_t *softc; { + ipf_lookup_softc_t *softl; + ipf_lookup_t **l; + int i; + + KMALLOC(softl, ipf_lookup_softc_t *); + if (softl == NULL) + return NULL; + + bzero((char *)softl, sizeof(*softl)); + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + softl->ipf_back[i] = (*(*l)->ipfl_create)(softc); + if (softl->ipf_back[i] == NULL) { + ipf_lookup_soft_destroy(softc, softl); + return NULL; + } + } + + return softl; +} + - if (ip_pool_init() == -1) - return -1; +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_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 */ +/* */ +/* Initialise all of the subcomponents of the lookup infrstructure. */ +/* ------------------------------------------------------------------------ */ +int +ipf_lookup_soft_init(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; + int err = 0; + int i; - RWLOCK_INIT(&ip_poolrw, "ip pool rwlock"); + for (i = 0; i < MAX_BACKENDS; i++) { + err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]); + if (err != 0) + break; + } - ip_lookup_inited = 1; + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_soft_fini */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* Call the fini function in each backend to cleanup all allocated data. */ +/* ------------------------------------------------------------------------ */ +int +ipf_lookup_soft_fini(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; + int i; + + for (i = 0; i < MAX_BACKENDS; i++) { + if (softl->ipf_back[i] != NULL) + (*backends[i]->ipfl_fini)(softc, + softl->ipf_back[i]); + } return 0; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_unload */ +/* Function: ipf_lookup_expire */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* */ +/* Step through each of the backends and call their expire functions, */ +/* allowing them to delete any lifetime limited data. */ +/* ------------------------------------------------------------------------ */ +void +ipf_lookup_expire(softc) + ipf_main_softc_t *softc; +{ + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + int i; + + WRITE_ENTER(&softc->ipf_poolrw); + for (i = 0; i < MAX_BACKENDS; i++) + (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]); + RWLOCK_EXIT(&softc->ipf_poolrw); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_softc_destroy */ /* Returns: int - 0 = success, else error */ -/* Parameters: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ /* */ /* Free up all pool related memory that has been allocated whilst IPFilter */ /* has been running. Also, do any other deinitialisation required such */ -/* ip_lookup_init() can be called again, safely. */ +/* ipf_lookup_init() can be called again, safely. */ /* ------------------------------------------------------------------------ */ -void ip_lookup_unload() +void +ipf_lookup_soft_destroy(softc, arg) + ipf_main_softc_t *softc; + void *arg; { - ip_pool_fini(); - fr_htable_unload(); + ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg; + int i; - if (ip_lookup_inited == 1) { - RW_DESTROY(&ip_poolrw); - ip_lookup_inited = 0; + for (i = 0; i < MAX_BACKENDS; i++) { + if (softl->ipf_back[i] != NULL) + (*backends[i]->ipfl_destroy)(softc, + softl->ipf_back[i]); } + + KFREE(softl); } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_ioctl */ +/* Function: ipf_lookup_ioctl */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* data(IO) - pointer to ioctl data to be copied to/from user */ /* space. */ /* cmd(I) - ioctl command number */ /* mode(I) - file mode bits used with open */ +/* uid(I) - uid of process doing ioctl */ +/* ctx(I) - pointer that represents context for uid */ /* */ /* Handle ioctl commands sent to the ioctl device. For the most part, this */ /* involves just calling another function to handle the specifics of each */ /* command. */ /* ------------------------------------------------------------------------ */ -int ip_lookup_ioctl(data, cmd, mode, uid, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode, uid; -void *ctx; +int +ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx) + ipf_main_softc_t *softc; + caddr_t data; + ioctlcmd_t cmd; + int mode, uid; + void *ctx; { int err; SPL_INT(s); @@ -145,52 +265,53 @@ void *ctx; { case SIOCLOOKUPADDNODE : case SIOCLOOKUPADDNODEW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_addnode(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_addnode(softc, data, uid); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPDELNODE : case SIOCLOOKUPDELNODEW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_delnode(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_delnode(softc, data, uid); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPADDTABLE : - WRITE_ENTER(&ip_poolrw); - err = iplookup_addtable(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_addtable(softc, data); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPDELTABLE : - WRITE_ENTER(&ip_poolrw); - err = iplookup_deltable(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_deltable(softc, data); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPSTAT : case SIOCLOOKUPSTATW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_stats(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_stats(softc, data); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPFLUSH : - WRITE_ENTER(&ip_poolrw); - err = iplookup_flush(data); - RWLOCK_EXIT(&ip_poolrw); + WRITE_ENTER(&softc->ipf_poolrw); + err = ipf_lookup_flush(softc, data); + RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPITER : - err = iplookup_iterate(data, uid, ctx); + err = ipf_lookup_iterate(softc, data, uid, ctx); break; case SIOCIPFDELTOK : - err = iplookup_deltok(data, uid, ctx); + err = ipf_lookup_deltok(softc, data, uid, ctx); break; default : + IPFERROR(50001); err = EINVAL; break; } @@ -200,192 +321,155 @@ void *ctx; /* ------------------------------------------------------------------------ */ -/* Function: iplookup_addnode */ +/* Function: ipf_lookup_addnode */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Add a new data node to a lookup structure. First, check to see if the */ /* parent structure refered to by name exists and if it does, then go on to */ /* add a node to it. */ /* ------------------------------------------------------------------------ */ -static int iplookup_addnode(data) -caddr_t data; +static int +ipf_lookup_addnode(softc, data, uid) + ipf_main_softc_t *softc; + caddr_t data; + int uid; { - ip_pool_node_t node, *m; + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; iplookupop_t op; - iphtable_t *iph; - iphtent_t hte; - ip_pool_t *p; + ipf_lookup_t **l; int err; + int i; err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50002); return EFAULT; + } - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && + (op.iplo_unit != IPLT_ALL)) { + IPFERROR(50003); return EINVAL; + } op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; - switch (op.iplo_type) - { - case IPLT_POOL : - if (op.iplo_size != sizeof(node)) - return EINVAL; - - err = COPYIN(op.iplo_struct, &node, sizeof(node)); - if (err != 0) - return EFAULT; - - p = ip_pool_find(op.iplo_unit, op.iplo_name); - if (p == NULL) - return ESRCH; - - /* - * add an entry to a pool - return an error if it already - * exists remove an entry from a pool - if it exists - * - in both cases, the pool *must* exist! - */ - m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask); - if (m) - return EEXIST; - err = ip_pool_insert(p, &node.ipn_addr.adf_addr, - &node.ipn_mask.adf_addr, node.ipn_info); - break; - - case IPLT_HASH : - if (op.iplo_size != sizeof(hte)) - return EINVAL; - - err = COPYIN(op.iplo_struct, &hte, sizeof(hte)); - if (err != 0) - return EFAULT; - - iph = fr_findhtable(op.iplo_unit, op.iplo_name); - if (iph == NULL) - return ESRCH; - err = fr_addhtent(iph, &hte); - break; + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (op.iplo_type == (*l)->ipfl_type) { + err = (*(*l)->ipfl_node_add)(softc, + softl->ipf_back[i], + &op, uid); + break; + } + } - default : + if (i == MAX_BACKENDS) { + IPFERROR(50012); err = EINVAL; - break; } + return err; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_delnode */ +/* Function: ipf_lookup_delnode */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Delete a node from a lookup table by first looking for the table it is */ /* in and then deleting the entry that gets found. */ /* ------------------------------------------------------------------------ */ -static int iplookup_delnode(data) -caddr_t data; +static int +ipf_lookup_delnode(softc, data, uid) + ipf_main_softc_t *softc; + caddr_t data; + int uid; { - ip_pool_node_t node, *m; + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; iplookupop_t op; - iphtable_t *iph; - iphtent_t hte; - ip_pool_t *p; + ipf_lookup_t **l; int err; + int i; err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50042); return EFAULT; + } - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && + (op.iplo_unit != IPLT_ALL)) { + IPFERROR(50013); return EINVAL; + } op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; - switch (op.iplo_type) - { - case IPLT_POOL : - if (op.iplo_size != sizeof(node)) - return EINVAL; - - err = COPYIN(op.iplo_struct, &node, sizeof(node)); - if (err != 0) - return EFAULT; - - p = ip_pool_find(op.iplo_unit, op.iplo_name); - if (!p) - return ESRCH; - - m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask); - if (m == NULL) - return ENOENT; - err = ip_pool_remove(p, m); - break; - - case IPLT_HASH : - if (op.iplo_size != sizeof(hte)) - return EINVAL; - - err = COPYIN(op.iplo_struct, &hte, sizeof(hte)); - if (err != 0) - return EFAULT; - - iph = fr_findhtable(op.iplo_unit, op.iplo_name); - if (iph == NULL) - return ESRCH; - err = fr_delhtent(iph, &hte); - break; + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (op.iplo_type == (*l)->ipfl_type) { + err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i], + &op, uid); + break; + } + } - default : + if (i == MAX_BACKENDS) { + IPFERROR(50021); err = EINVAL; - break; } return err; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_addtable */ +/* Function: ipf_lookup_addtable */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Create a new lookup table, if one doesn't already exist using the name */ /* for this one. */ /* ------------------------------------------------------------------------ */ -static int iplookup_addtable(data) -caddr_t data; +static int +ipf_lookup_addtable(softc, data) + ipf_main_softc_t *softc; + caddr_t data; { + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; iplookupop_t op; - int err; + ipf_lookup_t **l; + int err, i; err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50022); return EFAULT; + } - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && + (op.iplo_unit != IPLT_ALL)) { + IPFERROR(50023); return EINVAL; + } op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; - switch (op.iplo_type) - { - case IPLT_POOL : - if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL) - err = EEXIST; - else - err = ip_pool_create(&op); - break; - - case IPLT_HASH : - if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL) - err = EEXIST; - else - err = fr_newhtable(&op); - break; + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (op.iplo_type == (*l)->ipfl_type) { + err = (*(*l)->ipfl_table_add)(softc, + softl->ipf_back[i], + &op); + break; + } + } - default : + if (i == MAX_BACKENDS) { + IPFERROR(50026); err = EINVAL; - break; } /* @@ -394,8 +478,10 @@ caddr_t data; */ if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { err = BCOPYOUT(&op, data, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50027); err = EFAULT; + } } return err; @@ -403,260 +489,317 @@ caddr_t data; /* ------------------------------------------------------------------------ */ -/* Function: iplookup_deltable */ +/* Function: ipf_lookup_deltable */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Decodes ioctl request to remove a particular hash table or pool and */ /* calls the relevant function to do the cleanup. */ /* ------------------------------------------------------------------------ */ -static int iplookup_deltable(data) -caddr_t data; +static int +ipf_lookup_deltable(softc, data) + ipf_main_softc_t *softc; + caddr_t data; { + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; iplookupop_t op; - int err; + ipf_lookup_t **l; + int err, i; err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50028); return EFAULT; + } - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && + (op.iplo_unit != IPLT_ALL)) { + IPFERROR(50029); return EINVAL; + } op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; - /* - * create a new pool - fail if one already exists with - * the same # - */ - switch (op.iplo_type) - { - case IPLT_POOL : - err = ip_pool_destroy(op.iplo_unit, op.iplo_name); - break; - - case IPLT_HASH : - err = fr_removehtable(op.iplo_unit, op.iplo_name); - break; + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (op.iplo_type == (*l)->ipfl_type) { + err = (*(*l)->ipfl_table_del)(softc, + softl->ipf_back[i], + &op); + break; + } + } - default : + if (i == MAX_BACKENDS) { + IPFERROR(50030); err = EINVAL; - break; } return err; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_stats */ +/* Function: ipf_lookup_stats */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Copy statistical information from inside the kernel back to user space. */ /* ------------------------------------------------------------------------ */ -static int iplookup_stats(data) -caddr_t data; +static int +ipf_lookup_stats(softc, data) + ipf_main_softc_t *softc; + caddr_t data; { + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; iplookupop_t op; + ipf_lookup_t **l; int err; + int i; err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) + if (err != 0) { + IPFERROR(50031); return EFAULT; + } - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) && + (op.iplo_unit != IPLT_ALL)) { + IPFERROR(50032); return EINVAL; + } - switch (op.iplo_type) - { - case IPLT_POOL : - err = ip_pool_statistics(&op); - break; - - case IPLT_HASH : - err = fr_gethtablestat(&op); - break; + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (op.iplo_type == (*l)->ipfl_type) { + err = (*(*l)->ipfl_stats_get)(softc, + softl->ipf_back[i], + &op); + break; + } + } - default : + if (i == MAX_BACKENDS) { + IPFERROR(50033); err = EINVAL; - break; } + return err; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_flush */ +/* Function: ipf_lookup_flush */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* */ /* A flush is called when we want to flush all the nodes from a particular */ /* entry in the hash table/pool or want to remove all groups from those. */ /* ------------------------------------------------------------------------ */ -static int iplookup_flush(data) -caddr_t data; +static int +ipf_lookup_flush(softc, data) + ipf_main_softc_t *softc; + caddr_t data; { - int err, unit, num, type; + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + int err, unit, num, type, i; iplookupflush_t flush; + ipf_lookup_t **l; err = BCOPYIN(data, &flush, sizeof(flush)); - if (err != 0) + if (err != 0) { + IPFERROR(50034); return EFAULT; + } unit = flush.iplf_unit; - if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) + if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) { + IPFERROR(50035); return EINVAL; + } flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; type = flush.iplf_type; + IPFERROR(50036); err = EINVAL; num = 0; - if (type == IPLT_POOL || type == IPLT_ALL) { - err = 0; - num = ip_pool_flush(&flush); - } - - if (type == IPLT_HASH || type == IPLT_ALL) { - err = 0; - num += fr_flushhtable(&flush); + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (type == (*l)->ipfl_type || type == IPLT_ALL) { + err = 0; + num += (*(*l)->ipfl_flush)(softc, + softl->ipf_back[i], + &flush); + } } if (err == 0) { flush.iplf_count = num; err = BCOPYOUT(&flush, data, sizeof(flush)); - if (err != 0) + if (err != 0) { + IPFERROR(50037); err = EFAULT; + } } return err; } /* ------------------------------------------------------------------------ */ -/* Function: ip_lookup_delref */ +/* Function: ipf_lookup_delref */ /* Returns: void */ -/* Parameters: type(I) - table type to operate on */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* type(I) - table type to operate on */ /* ptr(I) - pointer to object to remove reference for */ /* */ /* This function organises calling the correct deref function for a given */ /* type of object being passed into it. */ /* ------------------------------------------------------------------------ */ -void ip_lookup_deref(type, ptr) -int type; -void *ptr; +void +ipf_lookup_deref(softc, type, ptr) + ipf_main_softc_t *softc; + int type; + void *ptr; { + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + int i; + if (ptr == NULL) return; - WRITE_ENTER(&ip_poolrw); - switch (type) - { - case IPLT_POOL : - ip_pool_deref(ptr); - break; - - case IPLT_HASH : - fr_derefhtable(ptr); - break; + for (i = 0; i < MAX_BACKENDS; i++) { + if (type == backends[i]->ipfl_type) { + WRITE_ENTER(&softc->ipf_poolrw); + (*backends[i]->ipfl_table_deref)(softc, + softl->ipf_back[i], + ptr); + RWLOCK_EXIT(&softc->ipf_poolrw); + break; + } } - RWLOCK_EXIT(&ip_poolrw); } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_iterate */ +/* Function: ipf_lookup_iterate */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* uid(I) - uid of caller */ /* ctx(I) - pointer to give the uid context */ /* */ /* Decodes ioctl request to step through either hash tables or pools. */ /* ------------------------------------------------------------------------ */ -static int iplookup_iterate(data, uid, ctx) -void *data; -int uid; -void *ctx; +static int +ipf_lookup_iterate(softc, data, uid, ctx) + ipf_main_softc_t *softc; + void *data; + int uid; + void *ctx; { + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; ipflookupiter_t iter; ipftoken_t *token; - int err; + int err, i; SPL_INT(s); - err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER); + err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER); if (err != 0) return err; - if (iter.ili_unit > IPL_LOGMAX) + if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) { + IPFERROR(50038); return EINVAL; + } - if (iter.ili_ival != IPFGENITER_LOOKUP) + if (iter.ili_ival != IPFGENITER_LOOKUP) { + IPFERROR(50039); return EINVAL; + } SPL_SCHED(s); - token = ipf_findtoken(iter.ili_key, uid, ctx); + token = ipf_token_find(softc, iter.ili_key, uid, ctx); if (token == NULL) { - RWLOCK_EXIT(&ipf_tokens); SPL_X(s); + IPFERROR(50040); return ESRCH; } - switch (iter.ili_type) - { - case IPLT_POOL : - err = ip_pool_getnext(token, &iter); - break; - case IPLT_HASH : - err = fr_htable_getnext(token, &iter); - break; - default : - err = EINVAL; - break; + for (i = 0; i < MAX_BACKENDS; i++) { + if (iter.ili_type == backends[i]->ipfl_type) { + err = (*backends[i]->ipfl_iter_next)(softc, + softl->ipf_back[i], + token, &iter); + break; + } } - RWLOCK_EXIT(&ipf_tokens); SPL_X(s); + if (i == MAX_BACKENDS) { + IPFERROR(50041); + err = EINVAL; + } + + WRITE_ENTER(&softc->ipf_tokens); + ipf_token_deref(softc, token); + RWLOCK_EXIT(&softc->ipf_tokens); + return err; } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_iterderef */ -/* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Function: ipf_lookup_iterderef */ +/* Returns: void */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* type(I) - backend type to iterate through */ +/* data(I) - pointer to data from ioctl call */ /* */ /* Decodes ioctl request to remove a particular hash table or pool and */ /* calls the relevant function to do the cleanup. */ +/* Because each of the backend types has a different data structure, */ +/* iteration is limited to one type at a time (i.e. it is not permitted to */ +/* go on from pool types to hash types as part of the "get next".) */ /* ------------------------------------------------------------------------ */ -void ip_lookup_iterderef(type, data) -u_32_t type; -void *data; +void +ipf_lookup_iterderef(softc, type, data) + ipf_main_softc_t *softc; + u_32_t type; + void *data; { - iplookupiterkey_t key; + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + struct iplookupiterkey *lkey; + iplookupiterkey_t key; + int i; key.ilik_key = type; + lkey = &key.ilik_unstr; - if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP) + if (lkey->ilik_ival != IPFGENITER_LOOKUP) return; - switch (key.ilik_unstr.ilik_type) - { - case IPLT_HASH : - fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype, - (int)key.ilik_unstr.ilik_unit, data); - break; - case IPLT_POOL : - ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype, - (int)key.ilik_unstr.ilik_unit, data); - break; + WRITE_ENTER(&softc->ipf_poolrw); + + for (i = 0; i < MAX_BACKENDS; i++) { + if (lkey->ilik_type == backends[i]->ipfl_type) { + (*backends[i]->ipfl_iter_deref)(softc, + softl->ipf_back[i], + lkey->ilik_otype, + lkey->ilik_unit, + data); + break; + } } + RWLOCK_EXIT(&softc->ipf_poolrw); } /* ------------------------------------------------------------------------ */ -/* Function: iplookup_deltok */ +/* Function: ipf_lookup_deltok */ /* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* data(I) - pointer to data from ioctl call */ /* uid(I) - uid of caller */ /* ctx(I) - pointer to give the uid context */ /* */ @@ -664,32 +807,198 @@ void *data; /* "key" is a combination of the table type, iterator type and the unit for */ /* which the token was being used. */ /* ------------------------------------------------------------------------ */ -static int iplookup_deltok(data, uid, ctx) -void *data; -int uid; -void *ctx; +int +ipf_lookup_deltok(softc, data, uid, ctx) + ipf_main_softc_t *softc; + void *data; + int uid; + void *ctx; { int error, key; SPL_INT(s); SPL_SCHED(s); - error = BCOPYIN(data, &key, sizeof(key)); + error = BCOPYIN(data, &key, sizeof(key)); if (error == 0) - error = ipf_deltoken(key, uid, ctx); + error = ipf_token_del(softc, key, uid, ctx); SPL_X(s); return error; } -#else /* IPFILTER_LOOKUP */ +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_res_num */ +/* Returns: void * - NULL = failure, else success. */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* unit(I) - device for which this is for */ +/* type(I) - type of lookup these parameters are for. */ +/* number(I) - table number to use when searching */ +/* funcptr(IO) - pointer to pointer for storing IP address */ +/* searching function. */ +/* */ +/* Search for the "table" number passed in amongst those configured for */ +/* that particular type. If the type is recognised then the function to */ +/* call to do the IP address search will be change, regardless of whether */ +/* or not the "table" number exists. */ +/* ------------------------------------------------------------------------ */ +void * +ipf_lookup_res_num(softc, unit, type, number, funcptr) + ipf_main_softc_t *softc; + int unit; + u_int type; + u_int number; + lookupfunc_t *funcptr; +{ + char name[FR_GROUPLEN]; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%u", number); +#else + (void) sprintf(name, "%u", number); +#endif + + return ipf_lookup_res_name(softc, unit, type, name, funcptr); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_res_name */ +/* Returns: void * - NULL = failure, else success. */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* unit(I) - device for which this is for */ +/* type(I) - type of lookup these parameters are for. */ +/* name(I) - table name to use when searching */ +/* funcptr(IO) - pointer to pointer for storing IP address */ +/* searching function. */ +/* */ +/* Search for the "table" number passed in amongst those configured for */ +/* that particular type. If the type is recognised then the function to */ +/* call to do the IP address search will be changed, regardless of whether */ +/* or not the "table" number exists. */ +/* ------------------------------------------------------------------------ */ +void * +ipf_lookup_res_name(softc, unit, type, name, funcptr) + ipf_main_softc_t *softc; + int unit; + u_int type; + char *name; + lookupfunc_t *funcptr; +{ + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + ipf_lookup_t **l; + void *ptr = NULL; + int i; + + READ_ENTER(&softc->ipf_poolrw); + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) { + if (type == (*l)->ipfl_type) { + ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i], + unit, name); + if (ptr != NULL && funcptr != NULL) { + *funcptr = (*l)->ipfl_addr_find; + } + break; + } + } + + if (i == MAX_BACKENDS) { + ptr = NULL; + if (funcptr != NULL) + *funcptr = NULL; + } + + RWLOCK_EXIT(&softc->ipf_poolrw); + + return ptr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_find_htable */ +/* Returns: void * - NULL = failure, else success. */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* unit(I) - device for which this is for */ +/* name(I) - table name to use when searching */ +/* */ +/* To support the group-map feature, where a hash table maps address */ +/* networks to rule group numbers, we need to expose a function that uses */ +/* only the hash table backend. */ +/* ------------------------------------------------------------------------ */ +void * +ipf_lookup_find_htable(softc, unit, name) + ipf_main_softc_t *softc; + int unit; + char *name; +{ + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + ipf_lookup_t **l; + void *tab = NULL; + int i; + + READ_ENTER(&softc->ipf_poolrw); + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) + if (IPLT_HASH == (*l)->ipfl_type) { + tab = ipf_htable_find(softl->ipf_back[i], unit, name); + break; + } + + RWLOCK_EXIT(&softc->ipf_poolrw); + + return tab; +} + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_lookup_sync */ +/* Returns: void */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* */ +/* This function is the interface that the machine dependent sync functions */ +/* call when a network interface name change occurs. It then calls the sync */ +/* functions of the lookup implementations - if they have one. */ +/* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -int ip_lookup_ioctl(data, cmd, mode, uid, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode, uid; -void *ctx; +void +ipf_lookup_sync(softc, ifp) + ipf_main_softc_t *softc; + void *ifp; { - return EIO; + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + ipf_lookup_t **l; + int i; + + READ_ENTER(&softc->ipf_poolrw); + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) + if ((*l)->ipfl_sync != NULL) + (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]); + + RWLOCK_EXIT(&softc->ipf_poolrw); } -#endif /* IPFILTER_LOOKUP */ + + +#ifndef _KERNEL +void +ipf_lookup_dump(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; + ipf_lookup_t **l; + int i; + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) + if (IPLT_POOL == (*l)->ipfl_type) { + ipf_pool_dump(softc, softl->ipf_back[i]); + break; + } + + for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) + if (IPLT_HASH == (*l)->ipfl_type) { + ipf_htable_dump(softc, softl->ipf_back[i]); + break; + } +} +#endif |