]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/ip_lookup.c
This commit was generated by cvs2svn to compensate for changes in r146773,
[FreeBSD/FreeBSD.git] / contrib / ipfilter / ip_lookup.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2002-2003 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/param.h>
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/file.h>
22 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
23 # include <sys/fcntl.h>
24 # include <sys/filio.h>
25 #else
26 # include <sys/ioctl.h>
27 #endif
28 #if !defined(_KERNEL)
29 # include <string.h>
30 # define _KERNEL
31 # ifdef __OpenBSD__
32 struct file;
33 # endif
34 # include <sys/uio.h>
35 # undef _KERNEL
36 #endif
37 #include <sys/socket.h>
38 #if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
39 # ifdef __osf__
40 #  include <net/radix.h>
41 # endif
42 # include "radix_ipf_local.h"
43 # define _RADIX_H_
44 #endif
45 #include <net/if.h>
46 #if defined(__FreeBSD__)
47 #  include <sys/cdefs.h>
48 #  include <sys/proc.h>
49 #endif
50 #if defined(_KERNEL)
51 # include <sys/systm.h>
52 # if !defined(__SVR4) && !defined(__svr4__)
53 #  include <sys/mbuf.h>
54 # endif
55 #endif
56 #include <netinet/in.h>
57
58 #include "netinet/ip_compat.h"
59 #include "netinet/ip_fil.h"
60 #include "netinet/ip_pool.h"
61 #include "netinet/ip_htable.h"
62 #include "netinet/ip_lookup.h"
63 /* END OF INCLUDES */
64
65 #if !defined(lint)
66 static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.5 2004/07/06 11:16:25 darrenr Exp";
67 #endif
68
69 #ifdef  IPFILTER_LOOKUP
70 int     ip_lookup_inited = 0;
71
72 static int iplookup_addnode __P((caddr_t));
73 static int iplookup_delnode __P((caddr_t data));
74 static int iplookup_addtable __P((caddr_t));
75 static int iplookup_deltable __P((caddr_t));
76 static int iplookup_stats __P((caddr_t));
77 static int iplookup_flush __P((caddr_t));
78
79
80 /* ------------------------------------------------------------------------ */
81 /* Function:    iplookup_init                                               */
82 /* Returns:     int     - 0 = success, else error                           */
83 /* Parameters:  Nil                                                         */
84 /*                                                                          */
85 /* Initialise all of the subcomponents of the lookup infrstructure.         */
86 /* ------------------------------------------------------------------------ */
87 int ip_lookup_init()
88 {
89
90         if (ip_pool_init() == -1)
91                 return -1;
92
93         RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
94
95         ip_lookup_inited = 1;
96
97         return 0;
98 }
99
100
101 /* ------------------------------------------------------------------------ */
102 /* Function:    iplookup_unload                                             */
103 /* Returns:     int     - 0 = success, else error                           */
104 /* Parameters:  Nil                                                         */
105 /*                                                                          */
106 /* Free up all pool related memory that has been allocated whilst IPFilter  */
107 /* has been running.  Also, do any other deinitialisation required such     */
108 /* ip_lookup_init() can be called again, safely.                            */
109 /* ------------------------------------------------------------------------ */
110 void ip_lookup_unload()
111 {
112         ip_pool_fini();
113         fr_htable_unload();
114
115         if (ip_lookup_inited == 1) {
116                 RW_DESTROY(&ip_poolrw);
117                 ip_lookup_inited = 0;
118         }
119 }
120
121
122 /* ------------------------------------------------------------------------ */
123 /* Function:    iplookup_ioctl                                              */
124 /* Returns:     int      - 0 = success, else error                          */
125 /* Parameters:  data(IO) - pointer to ioctl data to be copied to/from user  */
126 /*                         space.                                           */
127 /*              cmd(I)   - ioctl command number                             */
128 /*              mode(I)  - file mode bits used with open                    */
129 /*                                                                          */
130 /* Handle ioctl commands sent to the ioctl device.  For the most part, this */
131 /* involves just calling another function to handle the specifics of each   */
132 /* command.                                                                 */
133 /* ------------------------------------------------------------------------ */
134 int ip_lookup_ioctl(data, cmd, mode)
135 caddr_t data;
136 ioctlcmd_t cmd;
137 int mode;
138 {
139         int err;
140 # if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
141         int s;
142 # endif
143
144         mode = mode;    /* LINT */
145
146         SPL_NET(s);
147
148         switch (cmd)
149         {
150         case SIOCLOOKUPADDNODE :
151         case SIOCLOOKUPADDNODEW :
152                 WRITE_ENTER(&ip_poolrw);
153                 err = iplookup_addnode(data);
154                 RWLOCK_EXIT(&ip_poolrw);
155                 break;
156
157         case SIOCLOOKUPDELNODE :
158         case SIOCLOOKUPDELNODEW :
159                 WRITE_ENTER(&ip_poolrw);
160                 err = iplookup_delnode(data);
161                 RWLOCK_EXIT(&ip_poolrw);
162                 break;
163
164         case SIOCLOOKUPADDTABLE :
165                 WRITE_ENTER(&ip_poolrw);
166                 err = iplookup_addtable(data);
167                 RWLOCK_EXIT(&ip_poolrw);
168                 break;
169
170         case SIOCLOOKUPDELTABLE :
171                 WRITE_ENTER(&ip_poolrw);
172                 err = iplookup_deltable(data);
173                 RWLOCK_EXIT(&ip_poolrw);
174                 break;
175
176         case SIOCLOOKUPSTAT :
177         case SIOCLOOKUPSTATW :
178                 WRITE_ENTER(&ip_poolrw);
179                 err = iplookup_stats(data);
180                 RWLOCK_EXIT(&ip_poolrw);
181                 break;
182
183         case SIOCLOOKUPFLUSH :
184                 WRITE_ENTER(&ip_poolrw);
185                 err = iplookup_flush(data);
186                 RWLOCK_EXIT(&ip_poolrw);
187                 break;
188
189         default :
190                 err = EINVAL;
191                 break;
192         }
193         SPL_X(s);
194         return err;
195 }
196
197
198 /* ------------------------------------------------------------------------ */
199 /* Function:    iplookup_addnode                                            */
200 /* Returns:     int     - 0 = success, else error                           */
201 /* Parameters:  data(I) - pointer to data from ioctl call                   */
202 /*                                                                          */
203 /* Add a new data node to a lookup structure.  First, check to see if the   */
204 /* parent structure refered to by name exists and if it does, then go on to */
205 /* add a node to it.                                                        */
206 /* ------------------------------------------------------------------------ */
207 static int iplookup_addnode(data)
208 caddr_t data;
209 {
210         ip_pool_node_t node, *m;
211         iplookupop_t op;
212         iphtable_t *iph;
213         iphtent_t hte;
214         ip_pool_t *p;
215         int err;
216
217         err = 0;
218         BCOPYIN(data, &op, sizeof(op));
219         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
220
221         switch (op.iplo_type)
222         {
223         case IPLT_POOL :
224                 if (op.iplo_size != sizeof(node))
225                         return EINVAL;
226
227                 err = COPYIN(op.iplo_struct, &node, sizeof(node));
228                 if (err != 0)
229                         return EFAULT;
230
231                 p = ip_pool_find(op.iplo_unit, op.iplo_name);
232                 if (p == NULL)
233                         return ESRCH;
234
235                 /*
236                  * add an entry to a pool - return an error if it already
237                  * exists remove an entry from a pool - if it exists
238                  * - in both cases, the pool *must* exist!
239                  */
240                 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
241                 if (m)
242                         return EEXIST;
243                 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
244                                      &node.ipn_mask.adf_addr, node.ipn_info);
245                 break;
246
247         case IPLT_HASH :
248                 if (op.iplo_size != sizeof(hte))
249                         return EINVAL;
250
251                 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
252                 if (err != 0)
253                         return EFAULT;
254
255                 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
256                 if (iph == NULL)
257                         return ESRCH;
258                 err = fr_addhtent(iph, &hte);
259                 break;
260
261         default :
262                 err = EINVAL;
263                 break;
264         }
265         return err;
266 }
267
268
269 /* ------------------------------------------------------------------------ */
270 /* Function:    iplookup_delnode                                            */
271 /* Returns:     int     - 0 = success, else error                           */
272 /* Parameters:  data(I) - pointer to data from ioctl call                   */
273 /*                                                                          */
274 /* Delete a node from a lookup table by first looking for the table it is   */
275 /* in and then deleting the entry that gets found.                          */
276 /* ------------------------------------------------------------------------ */
277 static int iplookup_delnode(data)
278 caddr_t data;
279 {
280         ip_pool_node_t node, *m;
281         iplookupop_t op;
282         iphtable_t *iph;
283         iphtent_t hte;
284         ip_pool_t *p;
285         int err;
286
287         err = 0;
288         BCOPYIN(data, &op, sizeof(op));
289
290         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
291
292         switch (op.iplo_type)
293         {
294         case IPLT_POOL :
295                 if (op.iplo_size != sizeof(node))
296                         return EINVAL;
297
298                 err = COPYIN(op.iplo_struct, &node, sizeof(node));
299                 if (err != 0)
300                         return EFAULT;
301
302                 p = ip_pool_find(op.iplo_unit, op.iplo_name);
303                 if (!p)
304                         return ESRCH;
305
306                 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
307                 if (m == NULL)
308                         return ENOENT;
309                 err = ip_pool_remove(p, m);
310                 break;
311
312         case IPLT_HASH :
313                 if (op.iplo_size != sizeof(hte))
314                         return EINVAL;
315
316                 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
317                 if (err != 0)
318                         return EFAULT;
319
320                 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
321                 if (iph == NULL)
322                         return ESRCH;
323                 err = fr_delhtent(iph, &hte);
324                 break;
325
326         default :
327                 err = EINVAL;
328                 break;
329         }
330         return err;
331 }
332
333
334 /* ------------------------------------------------------------------------ */
335 /* Function:    iplookup_addtable                                           */
336 /* Returns:     int     - 0 = success, else error                           */
337 /* Parameters:  data(I) - pointer to data from ioctl call                   */
338 /*                                                                          */
339 /* Create a new lookup table, if one doesn't already exist using the name   */
340 /* for this one.                                                            */
341 /* ------------------------------------------------------------------------ */
342 static int iplookup_addtable(data)
343 caddr_t data;
344 {
345         iplookupop_t op;
346         int err;
347
348         err = 0;
349         BCOPYIN(data, &op, sizeof(op));
350
351         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
352
353         switch (op.iplo_type)
354         {
355         case IPLT_POOL :
356                 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
357                         err = EEXIST;
358                 else
359                         err = ip_pool_create(&op);
360                 break;
361
362         case IPLT_HASH :
363                 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
364                         err = EEXIST;
365                 else
366                         err = fr_newhtable(&op);
367                 break;
368
369         default :
370                 err = EINVAL;
371                 break;
372         }
373         return err;
374 }
375
376
377 /* ------------------------------------------------------------------------ */
378 /* Function:    iplookup_deltable                                           */
379 /* Returns:     int     - 0 = success, else error                           */
380 /* Parameters:  data(I) - pointer to data from ioctl call                   */
381 /*                                                                          */
382 /* Decodes ioctl request to remove a particular hash table or pool and      */
383 /* calls the relevant function to do the cleanup.                           */
384 /* ------------------------------------------------------------------------ */
385 static int iplookup_deltable(data)
386 caddr_t data;
387 {
388         iplookupop_t op;
389         int err;
390
391         BCOPYIN(data, &op, sizeof(op));
392         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
393
394         if (op.iplo_arg & IPLT_ANON)
395                 op.iplo_arg &= IPLT_ANON;
396
397         /*
398          * create a new pool - fail if one already exists with
399          * the same #
400          */
401         switch (op.iplo_type)
402         {
403         case IPLT_POOL :
404                 err = ip_pool_destroy(&op);
405                 break;
406
407         case IPLT_HASH :
408                 err = fr_removehtable(&op);
409                 break;
410
411         default :
412                 err = EINVAL;
413                 break;
414         }
415         return err;
416 }
417
418
419 /* ------------------------------------------------------------------------ */
420 /* Function:    iplookup_stats                                              */
421 /* Returns:     int     - 0 = success, else error                           */
422 /* Parameters:  data(I) - pointer to data from ioctl call                   */
423 /*                                                                          */
424 /* Copy statistical information from inside the kernel back to user space.  */
425 /* ------------------------------------------------------------------------ */
426 static int iplookup_stats(data)
427 caddr_t data;
428 {
429         iplookupop_t op;
430         int err;
431
432         err = 0;
433         BCOPYIN(data, &op, sizeof(op));
434
435         switch (op.iplo_type)
436         {
437         case IPLT_POOL :
438                 err = ip_pool_statistics(&op);
439                 break;
440
441         case IPLT_HASH :
442                 err = fr_gethtablestat(&op);
443                 break;
444
445         default :
446                 err = EINVAL;
447                 break;
448         }
449         return err;
450 }
451
452
453 /* ------------------------------------------------------------------------ */
454 /* Function:    iplookup_flush                                              */
455 /* Returns:     int     - 0 = success, else error                           */
456 /* Parameters:  data(I) - pointer to data from ioctl call                   */
457 /*                                                                          */
458 /* A flush is called when we want to flush all the nodes from a particular  */
459 /* entry in the hash table/pool or want to remove all groups from those.    */
460 /* ------------------------------------------------------------------------ */
461 static int iplookup_flush(data)
462 caddr_t data;
463 {
464         int err, unit, num, type;
465         iplookupflush_t flush;
466
467         err = 0;
468         BCOPYIN(data, &flush, sizeof(flush));
469
470         flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
471
472         unit = flush.iplf_unit;
473         if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
474                 return EINVAL;
475
476         type = flush.iplf_type;
477         err = EINVAL;
478         num = 0;
479
480         if (type == IPLT_POOL || type == IPLT_ALL) {
481                 err = 0;
482                 num = ip_pool_flush(&flush);
483         }
484
485         if (type == IPLT_HASH  || type == IPLT_ALL) {
486                 err = 0;
487                 num += fr_flushhtable(&flush);
488         }
489
490         if (err == 0) {
491                 flush.iplf_count = num;
492                 err = COPYOUT(&flush, data, sizeof(flush));
493         }
494         return err;
495 }
496
497
498 void ip_lookup_deref(type, ptr)
499 int type;
500 void *ptr;
501 {
502         if (ptr == NULL)
503                 return;
504
505         WRITE_ENTER(&ip_poolrw);
506         switch (type)
507         {
508         case IPLT_POOL :
509                 ip_pool_deref(ptr);
510                 break;
511
512         case IPLT_HASH :
513                 fr_derefhtable(ptr);
514                 break;
515         }
516         RWLOCK_EXIT(&ip_poolrw);
517 }
518
519
520 #else /* IPFILTER_LOOKUP */
521
522 /*ARGSUSED*/
523 int ip_lookup_ioctl(data, cmd, mode)
524 caddr_t data;
525 ioctlcmd_t cmd;
526 int mode;
527 {
528         return EIO;
529 }
530 #endif /* IPFILTER_LOOKUP */