4 * Copyright (C) 2002-2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 #if defined(KERNEL) || defined(_KERNEL)
15 # define _PROTO_NET_H_
17 #include <sys/param.h>
18 #include <sys/errno.h>
19 #include <sys/types.h>
22 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
23 # include <sys/fcntl.h>
24 # include <sys/filio.h>
26 # include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
39 # include "radix_ipf_local.h"
43 #if defined(__FreeBSD__)
44 # include <sys/cdefs.h>
45 # include <sys/proc.h>
48 # include <sys/systm.h>
49 # if !defined(__SVR4) && !defined(__svr4__)
50 # include <sys/mbuf.h>
53 #include <netinet/in.h>
55 #include "netinet/ip_compat.h"
56 #include "netinet/ip_fil.h"
57 #include "netinet/ip_pool.h"
58 #include "netinet/ip_htable.h"
59 #include "netinet/ip_lookup.h"
63 static const char rcsid
[] = "@(#)Id: ip_lookup.c,v 2.35.2.21 2009/05/13 18:31:15 darrenr Exp";
66 #ifdef IPFILTER_LOOKUP
67 int ip_lookup_inited
= 0;
69 static int iplookup_addnode
__P((caddr_t
));
70 static int iplookup_delnode
__P((caddr_t data
));
71 static int iplookup_addtable
__P((caddr_t
));
72 static int iplookup_deltable
__P((caddr_t
));
73 static int iplookup_stats
__P((caddr_t
));
74 static int iplookup_flush
__P((caddr_t
));
75 static int iplookup_iterate
__P((void *, int, void *));
76 static int iplookup_deltok
__P((void *, int, void *));
79 /* ------------------------------------------------------------------------ */
80 /* Function: iplookup_init */
81 /* Returns: int - 0 = success, else error */
84 /* Initialise all of the subcomponents of the lookup infrstructure. */
85 /* ------------------------------------------------------------------------ */
89 if (ip_pool_init() == -1)
92 RWLOCK_INIT(&ip_poolrw
, "ip pool rwlock");
100 /* ------------------------------------------------------------------------ */
101 /* Function: iplookup_unload */
102 /* Returns: int - 0 = success, else error */
103 /* Parameters: Nil */
105 /* Free up all pool related memory that has been allocated whilst IPFilter */
106 /* has been running. Also, do any other deinitialisation required such */
107 /* ip_lookup_init() can be called again, safely. */
108 /* ------------------------------------------------------------------------ */
109 void ip_lookup_unload()
114 if (ip_lookup_inited
== 1) {
115 RW_DESTROY(&ip_poolrw
);
116 ip_lookup_inited
= 0;
121 /* ------------------------------------------------------------------------ */
122 /* Function: iplookup_ioctl */
123 /* Returns: int - 0 = success, else error */
124 /* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
126 /* cmd(I) - ioctl command number */
127 /* mode(I) - file mode bits used with open */
129 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
130 /* involves just calling another function to handle the specifics of each */
132 /* ------------------------------------------------------------------------ */
133 int ip_lookup_ioctl(data
, cmd
, mode
, uid
, ctx
)
142 mode
= mode
; /* LINT */
148 case SIOCLOOKUPADDNODE
:
149 case SIOCLOOKUPADDNODEW
:
150 WRITE_ENTER(&ip_poolrw
);
151 err
= iplookup_addnode(data
);
152 RWLOCK_EXIT(&ip_poolrw
);
155 case SIOCLOOKUPDELNODE
:
156 case SIOCLOOKUPDELNODEW
:
157 WRITE_ENTER(&ip_poolrw
);
158 err
= iplookup_delnode(data
);
159 RWLOCK_EXIT(&ip_poolrw
);
162 case SIOCLOOKUPADDTABLE
:
163 WRITE_ENTER(&ip_poolrw
);
164 err
= iplookup_addtable(data
);
165 RWLOCK_EXIT(&ip_poolrw
);
168 case SIOCLOOKUPDELTABLE
:
169 WRITE_ENTER(&ip_poolrw
);
170 err
= iplookup_deltable(data
);
171 RWLOCK_EXIT(&ip_poolrw
);
174 case SIOCLOOKUPSTAT
:
175 case SIOCLOOKUPSTATW
:
176 WRITE_ENTER(&ip_poolrw
);
177 err
= iplookup_stats(data
);
178 RWLOCK_EXIT(&ip_poolrw
);
181 case SIOCLOOKUPFLUSH
:
182 WRITE_ENTER(&ip_poolrw
);
183 err
= iplookup_flush(data
);
184 RWLOCK_EXIT(&ip_poolrw
);
187 case SIOCLOOKUPITER
:
188 err
= iplookup_iterate(data
, uid
, ctx
);
192 err
= iplookup_deltok(data
, uid
, ctx
);
204 /* ------------------------------------------------------------------------ */
205 /* Function: iplookup_addnode */
206 /* Returns: int - 0 = success, else error */
207 /* Parameters: data(I) - pointer to data from ioctl call */
209 /* Add a new data node to a lookup structure. First, check to see if the */
210 /* parent structure refered to by name exists and if it does, then go on to */
211 /* add a node to it. */
212 /* ------------------------------------------------------------------------ */
213 static int iplookup_addnode(data
)
216 ip_pool_node_t node
, *m
;
223 err
= BCOPYIN(data
, &op
, sizeof(op
));
227 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
230 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
232 switch (op
.iplo_type
)
235 if (op
.iplo_size
!= sizeof(node
))
238 err
= COPYIN(op
.iplo_struct
, &node
, sizeof(node
));
242 p
= ip_pool_find(op
.iplo_unit
, op
.iplo_name
);
247 * add an entry to a pool - return an error if it already
248 * exists remove an entry from a pool - if it exists
249 * - in both cases, the pool *must* exist!
251 m
= ip_pool_findeq(p
, &node
.ipn_addr
, &node
.ipn_mask
);
254 err
= ip_pool_insert(p
, &node
.ipn_addr
.adf_addr
,
255 &node
.ipn_mask
.adf_addr
, node
.ipn_info
);
259 if (op
.iplo_size
!= sizeof(hte
))
262 err
= COPYIN(op
.iplo_struct
, &hte
, sizeof(hte
));
266 iph
= fr_findhtable(op
.iplo_unit
, op
.iplo_name
);
269 err
= fr_addhtent(iph
, &hte
);
280 /* ------------------------------------------------------------------------ */
281 /* Function: iplookup_delnode */
282 /* Returns: int - 0 = success, else error */
283 /* Parameters: data(I) - pointer to data from ioctl call */
285 /* Delete a node from a lookup table by first looking for the table it is */
286 /* in and then deleting the entry that gets found. */
287 /* ------------------------------------------------------------------------ */
288 static int iplookup_delnode(data
)
291 ip_pool_node_t node
, *m
;
298 err
= BCOPYIN(data
, &op
, sizeof(op
));
302 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
305 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
307 switch (op
.iplo_type
)
310 if (op
.iplo_size
!= sizeof(node
))
313 err
= COPYIN(op
.iplo_struct
, &node
, sizeof(node
));
317 p
= ip_pool_find(op
.iplo_unit
, op
.iplo_name
);
321 m
= ip_pool_findeq(p
, &node
.ipn_addr
, &node
.ipn_mask
);
324 err
= ip_pool_remove(p
, m
);
328 if (op
.iplo_size
!= sizeof(hte
))
331 err
= COPYIN(op
.iplo_struct
, &hte
, sizeof(hte
));
335 iph
= fr_findhtable(op
.iplo_unit
, op
.iplo_name
);
338 err
= fr_delhtent(iph
, &hte
);
349 /* ------------------------------------------------------------------------ */
350 /* Function: iplookup_addtable */
351 /* Returns: int - 0 = success, else error */
352 /* Parameters: data(I) - pointer to data from ioctl call */
354 /* Create a new lookup table, if one doesn't already exist using the name */
356 /* ------------------------------------------------------------------------ */
357 static int iplookup_addtable(data
)
363 err
= BCOPYIN(data
, &op
, sizeof(op
));
367 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
370 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
372 switch (op
.iplo_type
)
375 if (ip_pool_find(op
.iplo_unit
, op
.iplo_name
) != NULL
)
378 err
= ip_pool_create(&op
);
382 if (fr_findhtable(op
.iplo_unit
, op
.iplo_name
) != NULL
)
385 err
= fr_newhtable(&op
);
394 * For anonymous pools, copy back the operation struct because in the
395 * case of success it will contain the new table's name.
397 if ((err
== 0) && ((op
.iplo_arg
& LOOKUP_ANON
) != 0)) {
398 err
= BCOPYOUT(&op
, data
, sizeof(op
));
407 /* ------------------------------------------------------------------------ */
408 /* Function: iplookup_deltable */
409 /* Returns: int - 0 = success, else error */
410 /* Parameters: data(I) - pointer to data from ioctl call */
412 /* Decodes ioctl request to remove a particular hash table or pool and */
413 /* calls the relevant function to do the cleanup. */
414 /* ------------------------------------------------------------------------ */
415 static int iplookup_deltable(data
)
421 err
= BCOPYIN(data
, &op
, sizeof(op
));
425 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
428 op
.iplo_name
[sizeof(op
.iplo_name
) - 1] = '\0';
431 * create a new pool - fail if one already exists with
434 switch (op
.iplo_type
)
437 err
= ip_pool_destroy(op
.iplo_unit
, op
.iplo_name
);
441 err
= fr_removehtable(op
.iplo_unit
, op
.iplo_name
);
452 /* ------------------------------------------------------------------------ */
453 /* Function: iplookup_stats */
454 /* Returns: int - 0 = success, else error */
455 /* Parameters: data(I) - pointer to data from ioctl call */
457 /* Copy statistical information from inside the kernel back to user space. */
458 /* ------------------------------------------------------------------------ */
459 static int iplookup_stats(data
)
465 err
= BCOPYIN(data
, &op
, sizeof(op
));
469 if (op
.iplo_unit
< 0 || op
.iplo_unit
> IPL_LOGMAX
)
472 switch (op
.iplo_type
)
475 err
= ip_pool_statistics(&op
);
479 err
= fr_gethtablestat(&op
);
490 /* ------------------------------------------------------------------------ */
491 /* Function: iplookup_flush */
492 /* Returns: int - 0 = success, else error */
493 /* Parameters: data(I) - pointer to data from ioctl call */
495 /* A flush is called when we want to flush all the nodes from a particular */
496 /* entry in the hash table/pool or want to remove all groups from those. */
497 /* ------------------------------------------------------------------------ */
498 static int iplookup_flush(data
)
501 int err
, unit
, num
, type
;
502 iplookupflush_t flush
;
504 err
= BCOPYIN(data
, &flush
, sizeof(flush
));
508 unit
= flush
.iplf_unit
;
509 if ((unit
< 0 || unit
> IPL_LOGMAX
) && (unit
!= IPLT_ALL
))
512 flush
.iplf_name
[sizeof(flush
.iplf_name
) - 1] = '\0';
514 type
= flush
.iplf_type
;
518 if (type
== IPLT_POOL
|| type
== IPLT_ALL
) {
520 num
= ip_pool_flush(&flush
);
523 if (type
== IPLT_HASH
|| type
== IPLT_ALL
) {
525 num
+= fr_flushhtable(&flush
);
529 flush
.iplf_count
= num
;
530 err
= BCOPYOUT(&flush
, data
, sizeof(flush
));
538 /* ------------------------------------------------------------------------ */
539 /* Function: ip_lookup_delref */
541 /* Parameters: type(I) - table type to operate on */
542 /* ptr(I) - pointer to object to remove reference for */
544 /* This function organises calling the correct deref function for a given */
545 /* type of object being passed into it. */
546 /* ------------------------------------------------------------------------ */
547 void ip_lookup_deref(type
, ptr
)
554 WRITE_ENTER(&ip_poolrw
);
565 RWLOCK_EXIT(&ip_poolrw
);
569 /* ------------------------------------------------------------------------ */
570 /* Function: iplookup_iterate */
571 /* Returns: int - 0 = success, else error */
572 /* Parameters: data(I) - pointer to data from ioctl call */
573 /* uid(I) - uid of caller */
574 /* ctx(I) - pointer to give the uid context */
576 /* Decodes ioctl request to step through either hash tables or pools. */
577 /* ------------------------------------------------------------------------ */
578 static int iplookup_iterate(data
, uid
, ctx
)
583 ipflookupiter_t iter
;
588 err
= fr_inobj(data
, &iter
, IPFOBJ_LOOKUPITER
);
592 if (iter
.ili_unit
> IPL_LOGMAX
)
595 if (iter
.ili_ival
!= IPFGENITER_LOOKUP
)
599 token
= ipf_findtoken(iter
.ili_key
, uid
, ctx
);
601 RWLOCK_EXIT(&ipf_tokens
);
606 switch (iter
.ili_type
)
609 err
= ip_pool_getnext(token
, &iter
);
612 err
= fr_htable_getnext(token
, &iter
);
619 WRITE_ENTER(&ipf_tokens
);
620 ipf_dereftoken(token
);
621 RWLOCK_EXIT(&ipf_tokens
);
628 /* ------------------------------------------------------------------------ */
629 /* Function: iplookup_iterderef */
630 /* Returns: int - 0 = success, else error */
631 /* Parameters: data(I) - pointer to data from ioctl call */
633 /* Decodes ioctl request to remove a particular hash table or pool and */
634 /* calls the relevant function to do the cleanup. */
635 /* ------------------------------------------------------------------------ */
636 void ip_lookup_iterderef(type
, data
)
640 iplookupiterkey_t key
;
644 if (key
.ilik_unstr
.ilik_ival
!= IPFGENITER_LOOKUP
)
647 switch (key
.ilik_unstr
.ilik_type
)
650 fr_htable_iterderef((u_int
)key
.ilik_unstr
.ilik_otype
,
651 (int)key
.ilik_unstr
.ilik_unit
, data
);
654 ip_pool_iterderef((u_int
)key
.ilik_unstr
.ilik_otype
,
655 (int)key
.ilik_unstr
.ilik_unit
, data
);
661 /* ------------------------------------------------------------------------ */
662 /* Function: iplookup_deltok */
663 /* Returns: int - 0 = success, else error */
664 /* Parameters: data(I) - pointer to data from ioctl call */
665 /* uid(I) - uid of caller */
666 /* ctx(I) - pointer to give the uid context */
668 /* Deletes the token identified by the combination of (type,uid,ctx) */
669 /* "key" is a combination of the table type, iterator type and the unit for */
670 /* which the token was being used. */
671 /* ------------------------------------------------------------------------ */
672 static int iplookup_deltok(data
, uid
, ctx
)
681 error
= BCOPYIN(data
, &key
, sizeof(key
));
683 error
= ipf_deltoken(key
, uid
, ctx
);
689 #else /* IPFILTER_LOOKUP */
692 int ip_lookup_ioctl(data
, cmd
, mode
, uid
, ctx
)
700 #endif /* IPFILTER_LOOKUP */