]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/ipfilter/netinet/ip_lookup.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / ipfilter / netinet / ip_lookup.c
1 /*
2  * Copyright (C) 2002-2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if defined(KERNEL) || defined(_KERNEL)
7 # undef KERNEL
8 # undef _KERNEL
9 # define        KERNEL  1
10 # define        _KERNEL 1
11 #endif
12 #if defined(__osf__)
13 # define _PROTO_NET_H_
14 #endif
15 #include <sys/param.h>
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/time.h>
19 #include <sys/file.h>
20 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
21 # include <sys/fcntl.h>
22 # include <sys/filio.h>
23 #else
24 # include <sys/ioctl.h>
25 #endif
26 #if !defined(_KERNEL)
27 # include <string.h>
28 # define _KERNEL
29 # ifdef __OpenBSD__
30 struct file;
31 # endif
32 # include <sys/uio.h>
33 # undef _KERNEL
34 #endif
35 #include <sys/socket.h>
36 #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
37 # include "radix_ipf_local.h"
38 # define _RADIX_H_
39 #endif
40 #include <net/if.h>
41 #if defined(__FreeBSD__)
42 #  include <sys/cdefs.h>
43 #  include <sys/proc.h>
44 #endif
45 #if defined(_KERNEL)
46 # include <sys/systm.h>
47 # if !defined(__SVR4) && !defined(__svr4__)
48 #  include <sys/mbuf.h>
49 # endif
50 #endif
51 #include <netinet/in.h>
52
53 #include "netinet/ip_compat.h"
54 #include "netinet/ip_fil.h"
55 #include "netinet/ip_pool.h"
56 #include "netinet/ip_htable.h"
57 #include "netinet/ip_lookup.h"
58 /* END OF INCLUDES */
59
60 #if !defined(lint)
61 static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.19 2007/10/11 09:05:51 darrenr Exp $";
62 #endif
63
64 #ifdef  IPFILTER_LOOKUP
65 int     ip_lookup_inited = 0;
66
67 static int iplookup_addnode __P((caddr_t));
68 static int iplookup_delnode __P((caddr_t data));
69 static int iplookup_addtable __P((caddr_t));
70 static int iplookup_deltable __P((caddr_t));
71 static int iplookup_stats __P((caddr_t));
72 static int iplookup_flush __P((caddr_t));
73 static int iplookup_iterate __P((void *, int, void *));
74 static int iplookup_deltok __P((void *, int, void *));
75
76
77 /* ------------------------------------------------------------------------ */
78 /* Function:    iplookup_init                                               */
79 /* Returns:     int     - 0 = success, else error                           */
80 /* Parameters:  Nil                                                         */
81 /*                                                                          */
82 /* Initialise all of the subcomponents of the lookup infrstructure.         */
83 /* ------------------------------------------------------------------------ */
84 int ip_lookup_init()
85 {
86
87         if (ip_pool_init() == -1)
88                 return -1;
89
90         RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
91
92         ip_lookup_inited = 1;
93
94         return 0;
95 }
96
97
98 /* ------------------------------------------------------------------------ */
99 /* Function:    iplookup_unload                                             */
100 /* Returns:     int     - 0 = success, else error                           */
101 /* Parameters:  Nil                                                         */
102 /*                                                                          */
103 /* Free up all pool related memory that has been allocated whilst IPFilter  */
104 /* has been running.  Also, do any other deinitialisation required such     */
105 /* ip_lookup_init() can be called again, safely.                            */
106 /* ------------------------------------------------------------------------ */
107 void ip_lookup_unload()
108 {
109         ip_pool_fini();
110         fr_htable_unload();
111
112         if (ip_lookup_inited == 1) {
113                 RW_DESTROY(&ip_poolrw);
114                 ip_lookup_inited = 0;
115         }
116 }
117
118
119 /* ------------------------------------------------------------------------ */
120 /* Function:    iplookup_ioctl                                              */
121 /* Returns:     int      - 0 = success, else error                          */
122 /* Parameters:  data(IO) - pointer to ioctl data to be copied to/from user  */
123 /*                         space.                                           */
124 /*              cmd(I)   - ioctl command number                             */
125 /*              mode(I)  - file mode bits used with open                    */
126 /*                                                                          */
127 /* Handle ioctl commands sent to the ioctl device.  For the most part, this */
128 /* involves just calling another function to handle the specifics of each   */
129 /* command.                                                                 */
130 /* ------------------------------------------------------------------------ */
131 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
132 caddr_t data;
133 ioctlcmd_t cmd;
134 int mode, uid;
135 void *ctx;
136 {
137         int err;
138         SPL_INT(s);
139
140         mode = mode;    /* LINT */
141
142         SPL_NET(s);
143
144         switch (cmd)
145         {
146         case SIOCLOOKUPADDNODE :
147         case SIOCLOOKUPADDNODEW :
148                 WRITE_ENTER(&ip_poolrw);
149                 err = iplookup_addnode(data);
150                 RWLOCK_EXIT(&ip_poolrw);
151                 break;
152
153         case SIOCLOOKUPDELNODE :
154         case SIOCLOOKUPDELNODEW :
155                 WRITE_ENTER(&ip_poolrw);
156                 err = iplookup_delnode(data);
157                 RWLOCK_EXIT(&ip_poolrw);
158                 break;
159
160         case SIOCLOOKUPADDTABLE :
161                 WRITE_ENTER(&ip_poolrw);
162                 err = iplookup_addtable(data);
163                 RWLOCK_EXIT(&ip_poolrw);
164                 break;
165
166         case SIOCLOOKUPDELTABLE :
167                 WRITE_ENTER(&ip_poolrw);
168                 err = iplookup_deltable(data);
169                 RWLOCK_EXIT(&ip_poolrw);
170                 break;
171
172         case SIOCLOOKUPSTAT :
173         case SIOCLOOKUPSTATW :
174                 WRITE_ENTER(&ip_poolrw);
175                 err = iplookup_stats(data);
176                 RWLOCK_EXIT(&ip_poolrw);
177                 break;
178
179         case SIOCLOOKUPFLUSH :
180                 WRITE_ENTER(&ip_poolrw);
181                 err = iplookup_flush(data);
182                 RWLOCK_EXIT(&ip_poolrw);
183                 break;
184
185         case SIOCLOOKUPITER :
186                 err = iplookup_iterate(data, uid, ctx);
187                 break;
188
189         case SIOCIPFDELTOK :
190                 err = iplookup_deltok(data, uid, ctx);
191                 break;
192
193         default :
194                 err = EINVAL;
195                 break;
196         }
197         SPL_X(s);
198         return err;
199 }
200
201
202 /* ------------------------------------------------------------------------ */
203 /* Function:    iplookup_addnode                                            */
204 /* Returns:     int     - 0 = success, else error                           */
205 /* Parameters:  data(I) - pointer to data from ioctl call                   */
206 /*                                                                          */
207 /* Add a new data node to a lookup structure.  First, check to see if the   */
208 /* parent structure refered to by name exists and if it does, then go on to */
209 /* add a node to it.                                                        */
210 /* ------------------------------------------------------------------------ */
211 static int iplookup_addnode(data)
212 caddr_t data;
213 {
214         ip_pool_node_t node, *m;
215         iplookupop_t op;
216         iphtable_t *iph;
217         iphtent_t hte;
218         ip_pool_t *p;
219         int err;
220
221         err = BCOPYIN(data, &op, sizeof(op));
222         if (err != 0)
223                 return EFAULT;
224
225         if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
226                 return EINVAL;
227
228         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
229
230         switch (op.iplo_type)
231         {
232         case IPLT_POOL :
233                 if (op.iplo_size != sizeof(node))
234                         return EINVAL;
235
236                 err = COPYIN(op.iplo_struct, &node, sizeof(node));
237                 if (err != 0)
238                         return EFAULT;
239
240                 p = ip_pool_find(op.iplo_unit, op.iplo_name);
241                 if (p == NULL)
242                         return ESRCH;
243
244                 /*
245                  * add an entry to a pool - return an error if it already
246                  * exists remove an entry from a pool - if it exists
247                  * - in both cases, the pool *must* exist!
248                  */
249                 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
250                 if (m)
251                         return EEXIST;
252                 err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
253                                      &node.ipn_mask.adf_addr, node.ipn_info);
254                 break;
255
256         case IPLT_HASH :
257                 if (op.iplo_size != sizeof(hte))
258                         return EINVAL;
259
260                 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
261                 if (err != 0)
262                         return EFAULT;
263
264                 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
265                 if (iph == NULL)
266                         return ESRCH;
267                 err = fr_addhtent(iph, &hte);
268                 break;
269
270         default :
271                 err = EINVAL;
272                 break;
273         }
274         return err;
275 }
276
277
278 /* ------------------------------------------------------------------------ */
279 /* Function:    iplookup_delnode                                            */
280 /* Returns:     int     - 0 = success, else error                           */
281 /* Parameters:  data(I) - pointer to data from ioctl call                   */
282 /*                                                                          */
283 /* Delete a node from a lookup table by first looking for the table it is   */
284 /* in and then deleting the entry that gets found.                          */
285 /* ------------------------------------------------------------------------ */
286 static int iplookup_delnode(data)
287 caddr_t data;
288 {
289         ip_pool_node_t node, *m;
290         iplookupop_t op;
291         iphtable_t *iph;
292         iphtent_t hte;
293         ip_pool_t *p;
294         int err;
295
296         err = BCOPYIN(data, &op, sizeof(op));
297         if (err != 0)
298                 return EFAULT;
299
300         if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
301                 return EINVAL;
302
303         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
304
305         switch (op.iplo_type)
306         {
307         case IPLT_POOL :
308                 if (op.iplo_size != sizeof(node))
309                         return EINVAL;
310
311                 err = COPYIN(op.iplo_struct, &node, sizeof(node));
312                 if (err != 0)
313                         return EFAULT;
314
315                 p = ip_pool_find(op.iplo_unit, op.iplo_name);
316                 if (!p)
317                         return ESRCH;
318
319                 m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
320                 if (m == NULL)
321                         return ENOENT;
322                 err = ip_pool_remove(p, m);
323                 break;
324
325         case IPLT_HASH :
326                 if (op.iplo_size != sizeof(hte))
327                         return EINVAL;
328
329                 err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
330                 if (err != 0)
331                         return EFAULT;
332
333                 iph = fr_findhtable(op.iplo_unit, op.iplo_name);
334                 if (iph == NULL)
335                         return ESRCH;
336                 err = fr_delhtent(iph, &hte);
337                 break;
338
339         default :
340                 err = EINVAL;
341                 break;
342         }
343         return err;
344 }
345
346
347 /* ------------------------------------------------------------------------ */
348 /* Function:    iplookup_addtable                                           */
349 /* Returns:     int     - 0 = success, else error                           */
350 /* Parameters:  data(I) - pointer to data from ioctl call                   */
351 /*                                                                          */
352 /* Create a new lookup table, if one doesn't already exist using the name   */
353 /* for this one.                                                            */
354 /* ------------------------------------------------------------------------ */
355 static int iplookup_addtable(data)
356 caddr_t data;
357 {
358         iplookupop_t op;
359         int err;
360
361         err = BCOPYIN(data, &op, sizeof(op));
362         if (err != 0)
363                 return EFAULT;
364
365         if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
366                 return EINVAL;
367
368         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
369
370         switch (op.iplo_type)
371         {
372         case IPLT_POOL :
373                 if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
374                         err = EEXIST;
375                 else
376                         err = ip_pool_create(&op);
377                 break;
378
379         case IPLT_HASH :
380                 if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
381                         err = EEXIST;
382                 else
383                         err = fr_newhtable(&op);
384                 break;
385
386         default :
387                 err = EINVAL;
388                 break;
389         }
390
391         /*
392          * For anonymous pools, copy back the operation struct because in the
393          * case of success it will contain the new table's name.
394          */
395         if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
396                 err = BCOPYOUT(&op, data, sizeof(op));
397                 if (err != 0)
398                         err = EFAULT;
399         }
400
401         return err;
402 }
403
404
405 /* ------------------------------------------------------------------------ */
406 /* Function:    iplookup_deltable                                           */
407 /* Returns:     int     - 0 = success, else error                           */
408 /* Parameters:  data(I) - pointer to data from ioctl call                   */
409 /*                                                                          */
410 /* Decodes ioctl request to remove a particular hash table or pool and      */
411 /* calls the relevant function to do the cleanup.                           */
412 /* ------------------------------------------------------------------------ */
413 static int iplookup_deltable(data)
414 caddr_t data;
415 {
416         iplookupop_t op;
417         int err;
418
419         err = BCOPYIN(data, &op, sizeof(op));
420         if (err != 0)
421                 return EFAULT;
422
423         if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
424                 return EINVAL;
425
426         op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
427
428         /*
429          * create a new pool - fail if one already exists with
430          * the same #
431          */
432         switch (op.iplo_type)
433         {
434         case IPLT_POOL :
435                 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
436                 break;
437
438         case IPLT_HASH :
439                 err = fr_removehtable(op.iplo_unit, op.iplo_name);
440                 break;
441
442         default :
443                 err = EINVAL;
444                 break;
445         }
446         return err;
447 }
448
449
450 /* ------------------------------------------------------------------------ */
451 /* Function:    iplookup_stats                                              */
452 /* Returns:     int     - 0 = success, else error                           */
453 /* Parameters:  data(I) - pointer to data from ioctl call                   */
454 /*                                                                          */
455 /* Copy statistical information from inside the kernel back to user space.  */
456 /* ------------------------------------------------------------------------ */
457 static int iplookup_stats(data)
458 caddr_t data;
459 {
460         iplookupop_t op;
461         int err;
462
463         err = BCOPYIN(data, &op, sizeof(op));
464         if (err != 0)
465                 return EFAULT;
466
467         if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
468                 return EINVAL;
469
470         switch (op.iplo_type)
471         {
472         case IPLT_POOL :
473                 err = ip_pool_statistics(&op);
474                 break;
475
476         case IPLT_HASH :
477                 err = fr_gethtablestat(&op);
478                 break;
479
480         default :
481                 err = EINVAL;
482                 break;
483         }
484         return err;
485 }
486
487
488 /* ------------------------------------------------------------------------ */
489 /* Function:    iplookup_flush                                              */
490 /* Returns:     int     - 0 = success, else error                           */
491 /* Parameters:  data(I) - pointer to data from ioctl call                   */
492 /*                                                                          */
493 /* A flush is called when we want to flush all the nodes from a particular  */
494 /* entry in the hash table/pool or want to remove all groups from those.    */
495 /* ------------------------------------------------------------------------ */
496 static int iplookup_flush(data)
497 caddr_t data;
498 {
499         int err, unit, num, type;
500         iplookupflush_t flush;
501
502         err = BCOPYIN(data, &flush, sizeof(flush));
503         if (err != 0)
504                 return EFAULT;
505
506         unit = flush.iplf_unit;
507         if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
508                 return EINVAL;
509
510         flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
511
512         type = flush.iplf_type;
513         err = EINVAL;
514         num = 0;
515
516         if (type == IPLT_POOL || type == IPLT_ALL) {
517                 err = 0;
518                 num = ip_pool_flush(&flush);
519         }
520
521         if (type == IPLT_HASH  || type == IPLT_ALL) {
522                 err = 0;
523                 num += fr_flushhtable(&flush);
524         }
525
526         if (err == 0) {
527                 flush.iplf_count = num;
528                 err = BCOPYOUT(&flush, data, sizeof(flush));
529                 if (err != 0)
530                         err = EFAULT;
531         }
532         return err;
533 }
534
535
536 /* ------------------------------------------------------------------------ */
537 /* Function:    ip_lookup_delref                                            */
538 /* Returns:     void                                                        */
539 /* Parameters:  type(I) - table type to operate on                          */
540 /*              ptr(I)  - pointer to object to remove reference for         */
541 /*                                                                          */
542 /* This function organises calling the correct deref function for a given   */
543 /* type of object being passed into it.                                     */
544 /* ------------------------------------------------------------------------ */
545 void ip_lookup_deref(type, ptr)
546 int type;
547 void *ptr;
548 {
549         if (ptr == NULL)
550                 return;
551
552         WRITE_ENTER(&ip_poolrw);
553         switch (type)
554         {
555         case IPLT_POOL :
556                 ip_pool_deref(ptr);
557                 break;
558
559         case IPLT_HASH :
560                 fr_derefhtable(ptr);
561                 break;
562         }
563         RWLOCK_EXIT(&ip_poolrw);
564 }
565
566
567 /* ------------------------------------------------------------------------ */
568 /* Function:    iplookup_iterate                                            */
569 /* Returns:     int     - 0 = success, else error                           */
570 /* Parameters:  data(I) - pointer to data from ioctl call                   */
571 /*              uid(I)  - uid of caller                                     */
572 /*              ctx(I)  - pointer to give the uid context                   */
573 /*                                                                          */
574 /* Decodes ioctl request to step through either hash tables or pools.       */
575 /* ------------------------------------------------------------------------ */
576 static int iplookup_iterate(data, uid, ctx)
577 void *data;
578 int uid;
579 void *ctx;
580 {
581         ipflookupiter_t iter;
582         ipftoken_t *token;
583         int err;
584         SPL_INT(s);
585
586         err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
587         if (err != 0)
588                 return err;
589
590         if (iter.ili_unit > IPL_LOGMAX)
591                 return EINVAL;
592
593         if (iter.ili_ival != IPFGENITER_LOOKUP)
594                 return EINVAL;
595
596         SPL_SCHED(s);
597         token = ipf_findtoken(iter.ili_key, uid, ctx);
598         if (token == NULL) {
599                 RWLOCK_EXIT(&ipf_tokens);
600                 SPL_X(s);
601                 return ESRCH;
602         }
603
604         switch (iter.ili_type)
605         {
606         case IPLT_POOL :
607                 err = ip_pool_getnext(token, &iter);
608                 break;
609         case IPLT_HASH :
610                 err = fr_htable_getnext(token, &iter);
611                 break;
612         default :
613                 err = EINVAL;
614                 break;
615         }
616         RWLOCK_EXIT(&ipf_tokens);
617         SPL_X(s);
618
619         return err;
620 }
621
622
623 /* ------------------------------------------------------------------------ */
624 /* Function:    iplookup_iterderef                                          */
625 /* Returns:     int     - 0 = success, else error                           */
626 /* Parameters:  data(I) - pointer to data from ioctl call                   */
627 /*                                                                          */
628 /* Decodes ioctl request to remove a particular hash table or pool and      */
629 /* calls the relevant function to do the cleanup.                           */
630 /* ------------------------------------------------------------------------ */
631 void ip_lookup_iterderef(type, data)
632 u_32_t type;
633 void *data;
634 {
635         iplookupiterkey_t       key;
636
637         key.ilik_key = type;
638
639         if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
640                 return;
641
642         switch (key.ilik_unstr.ilik_type)
643         {
644         case IPLT_HASH :
645                 fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
646                                     (int)key.ilik_unstr.ilik_unit, data);
647                 break;
648         case IPLT_POOL :
649                 ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
650                                   (int)key.ilik_unstr.ilik_unit, data);
651                 break;
652         }
653 }
654
655
656 /* ------------------------------------------------------------------------ */
657 /* Function:    iplookup_deltok                                             */
658 /* Returns:     int     - 0 = success, else error                           */
659 /* Parameters:  data(I) - pointer to data from ioctl call                   */
660 /*              uid(I)  - uid of caller                                     */
661 /*              ctx(I)  - pointer to give the uid context                   */
662 /*                                                                          */
663 /* Deletes the token identified by the combination of (type,uid,ctx)        */
664 /* "key" is a combination of the table type, iterator type and the unit for */
665 /* which the token was being used.                                          */
666 /* ------------------------------------------------------------------------ */
667 static int iplookup_deltok(data, uid, ctx)
668 void *data;
669 int uid;
670 void *ctx;
671 {
672         int error, key;
673         SPL_INT(s);
674
675         SPL_SCHED(s);
676         error = BCOPYIN(data, &key, sizeof(key)); 
677         if (error == 0)
678                 error = ipf_deltoken(key, uid, ctx);
679         SPL_X(s);
680         return error;
681 }
682
683
684 #else /* IPFILTER_LOOKUP */
685
686 /*ARGSUSED*/
687 int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
688 caddr_t data;
689 ioctlcmd_t cmd;
690 int mode, uid;
691 void *ctx;
692 {
693         return EIO;
694 }
695 #endif /* IPFILTER_LOOKUP */