ip_lookup.c revision 3448:aaf16568054b
114630Sokutsu/*
214630Sokutsu * Copyright (C) 2002-2003 by Darren Reed.
314630Sokutsu *
414630Sokutsu * See the IPFILTER.LICENCE file for details on licencing.
514630Sokutsu *
614630Sokutsu * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
714630Sokutsu * Use is subject to license terms.
814630Sokutsu */
914630Sokutsu
1014630Sokutsu#pragma ident	"%Z%%M%	%I%	%E% SMI"
1114630Sokutsu
1214630Sokutsu#if defined(KERNEL) || defined(_KERNEL)
1314630Sokutsu# undef KERNEL
1414630Sokutsu# undef _KERNEL
1514630Sokutsu# define        KERNEL	1
1614630Sokutsu# define        _KERNEL	1
1714630Sokutsu#endif
1814630Sokutsu#if defined(__osf__)
1914630Sokutsu# define _PROTO_NET_H_
2014630Sokutsu#endif
2114630Sokutsu#include <sys/param.h>
2214630Sokutsu#include <sys/errno.h>
2314630Sokutsu#include <sys/types.h>
2414630Sokutsu#include <sys/time.h>
2514630Sokutsu#include <sys/file.h>
2614630Sokutsu#if __FreeBSD_version >= 220000 && defined(_KERNEL)
2714630Sokutsu# include <sys/fcntl.h>
2815486Sshurailine# include <sys/filio.h>
2914630Sokutsu#else
3014630Sokutsu# include <sys/ioctl.h>
3114630Sokutsu#endif
3214630Sokutsu#if !defined(_KERNEL)
3314630Sokutsu# include <string.h>
3414630Sokutsu# define _KERNEL
3514630Sokutsu# ifdef __OpenBSD__
3614630Sokutsustruct file;
3714630Sokutsu# endif
3814630Sokutsu# include <sys/uio.h>
3914630Sokutsu# undef _KERNEL
4014630Sokutsu#endif
4114630Sokutsu#include <sys/socket.h>
4214630Sokutsu#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
4314630Sokutsu# ifdef __osf__
4414630Sokutsu#  include <net/radix.h>
4514630Sokutsu# endif
4614630Sokutsu# include "radix_ipf_local.h"
4714630Sokutsu# define _RADIX_H_
4814630Sokutsu#endif
4914630Sokutsu#include <net/if.h>
5014630Sokutsu#if defined(__FreeBSD__)
5114630Sokutsu#  include <sys/cdefs.h>
5214630Sokutsu#  include <sys/proc.h>
5314630Sokutsu#endif
5414630Sokutsu#if defined(_KERNEL)
5514630Sokutsu# include <sys/systm.h>
5614630Sokutsu# if !defined(__SVR4) && !defined(__svr4__)
5714630Sokutsu#  include <sys/mbuf.h>
5814630Sokutsu# endif
5914630Sokutsu#endif
6014630Sokutsu#include <netinet/in.h>
6114630Sokutsu
6214630Sokutsu#include "netinet/ip_compat.h"
6314630Sokutsu#include "netinet/ip_fil.h"
6414630Sokutsu#include "netinet/ip_pool.h"
6514630Sokutsu#include "netinet/ip_htable.h"
6614630Sokutsu#include "netinet/ip_lookup.h"
6714630Sokutsu#include "netinet/ipf_stack.h"
6814630Sokutsu/* END OF INCLUDES */
6914630Sokutsu
7014630Sokutsu#if !defined(lint)
7114630Sokutsustatic const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.7 2005/06/12 07:18:20 darrenr Exp $";
7214630Sokutsu#endif
7314630Sokutsu
7414630Sokutsu#ifdef	IPFILTER_LOOKUP
7514630Sokutsustatic int iplookup_addnode __P((caddr_t, ipf_stack_t *));
7614630Sokutsustatic int iplookup_delnode __P((caddr_t data, ipf_stack_t *));
7714630Sokutsustatic int iplookup_addtable __P((caddr_t, ipf_stack_t *));
7814630Sokutsustatic int iplookup_deltable __P((caddr_t, ipf_stack_t *));
7914630Sokutsustatic int iplookup_stats __P((caddr_t, ipf_stack_t *));
8014630Sokutsustatic int iplookup_flush __P((caddr_t, ipf_stack_t *));
8114630Sokutsu
8214630Sokutsu
8314630Sokutsu
8414630Sokutsu/* ------------------------------------------------------------------------ */
8514630Sokutsu/* Function:    iplookup_init                                               */
8614630Sokutsu/* Returns:     int     - 0 = success, else error                           */
8714630Sokutsu/* Parameters:  Nil                                                         */
8814630Sokutsu/*                                                                          */
8914630Sokutsu/* Initialise all of the subcomponents of the lookup infrstructure.         */
9014630Sokutsu/* ------------------------------------------------------------------------ */
9114630Sokutsuint ip_lookup_init(ifs)
9214630Sokutsuipf_stack_t *ifs;
9314630Sokutsu{
9414630Sokutsu
9514630Sokutsu	if (ip_pool_init(ifs) == -1)
9614630Sokutsu		return -1;
9714630Sokutsu
9814630Sokutsu	RWLOCK_INIT(&ifs->ifs_ip_poolrw, "ip pool rwlock");
9914630Sokutsu
10014630Sokutsu	ifs->ifs_ip_lookup_inited = 1;
10114630Sokutsu	ifs->ifs_ipftokenhead = NULL;
10214630Sokutsu	ifs->ifs_ipftokentail = &ifs->ifs_ipftokenhead;
10314630Sokutsu	return 0;
10414630Sokutsu}
10514630Sokutsu
10614630Sokutsu
10714630Sokutsu/* ------------------------------------------------------------------------ */
10814630Sokutsu/* Function:    iplookup_unload                                             */
10914630Sokutsu/* Returns:     int     - 0 = success, else error                           */
11014630Sokutsu/* Parameters:  Nil                                                         */
11114630Sokutsu/*                                                                          */
11214630Sokutsu/* Free up all pool related memory that has been allocated whilst IPFilter  */
11314630Sokutsu/* has been running.  Also, do any other deinitialisation required such     */
11414630Sokutsu/* ip_lookup_init() can be called again, safely.                            */
11514630Sokutsu/* ------------------------------------------------------------------------ */
11614630Sokutsuvoid ip_lookup_unload(ifs)
11714630Sokutsuipf_stack_t *ifs;
11814630Sokutsu{
11914630Sokutsu	ip_pool_fini(ifs);
12014630Sokutsu	fr_htable_unload(ifs);
12114630Sokutsu
12214630Sokutsu	if (ifs->ifs_ip_lookup_inited == 1) {
12314630Sokutsu		RW_DESTROY(&ifs->ifs_ip_poolrw);
12414630Sokutsu		ifs->ifs_ip_lookup_inited = 0;
12514630Sokutsu	}
12614630Sokutsu}
12714630Sokutsu
12814630Sokutsu
12914630Sokutsu/* ------------------------------------------------------------------------ */
13014630Sokutsu/* Function:    iplookup_ioctl                                              */
13114630Sokutsu/* Returns:     int      - 0 = success, else error                          */
13214630Sokutsu/* Parameters:  data(IO) - pointer to ioctl data to be copied to/from user  */
13314630Sokutsu/*                         space.                                           */
13414630Sokutsu/*              cmd(I)   - ioctl command number                             */
13514630Sokutsu/*              mode(I)  - file mode bits used with open                    */
13614630Sokutsu/*                                                                          */
13714630Sokutsu/* Handle ioctl commands sent to the ioctl device.  For the most part, this */
13814630Sokutsu/* involves just calling another function to handle the specifics of each   */
13914630Sokutsu/* command.                                                                 */
14014630Sokutsu/* ------------------------------------------------------------------------ */
14114630Sokutsuint ip_lookup_ioctl(data, cmd, mode, uid, ctx, ifs)
14214630Sokutsucaddr_t data;
143ioctlcmd_t cmd;
144int mode, uid;
145void *ctx;
146ipf_stack_t *ifs;
147{
148	int err;
149	SPL_INT(s);
150
151	mode = mode;	/* LINT */
152
153	SPL_NET(s);
154
155	switch (cmd)
156	{
157	case SIOCLOOKUPADDNODE :
158	case SIOCLOOKUPADDNODEW :
159		WRITE_ENTER(&ifs->ifs_ip_poolrw);
160		err = iplookup_addnode(data, ifs);
161		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
162		break;
163
164	case SIOCLOOKUPDELNODE :
165	case SIOCLOOKUPDELNODEW :
166		WRITE_ENTER(&ifs->ifs_ip_poolrw);
167		err = iplookup_delnode(data, ifs);
168		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
169		break;
170
171	case SIOCLOOKUPADDTABLE :
172		WRITE_ENTER(&ifs->ifs_ip_poolrw);
173		err = iplookup_addtable(data, ifs);
174		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
175		break;
176
177	case SIOCLOOKUPDELTABLE :
178		WRITE_ENTER(&ifs->ifs_ip_poolrw);
179		err = iplookup_deltable(data, ifs);
180		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
181		break;
182
183	case SIOCLOOKUPSTAT :
184	case SIOCLOOKUPSTATW :
185		WRITE_ENTER(&ifs->ifs_ip_poolrw);
186		err = iplookup_stats(data, ifs);
187		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
188		break;
189
190	case SIOCLOOKUPFLUSH :
191		WRITE_ENTER(&ifs->ifs_ip_poolrw);
192		err = iplookup_flush(data, ifs);
193		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
194		break;
195
196	case SIOCLOOKUPITER :
197		err = ip_lookup_iterate(data, uid, ctx, ifs);
198		break;
199
200	default :
201		err = EINVAL;
202		break;
203	}
204	SPL_X(s);
205	return err;
206}
207
208
209/* ------------------------------------------------------------------------ */
210/* Function:    iplookup_addnode                                            */
211/* Returns:     int     - 0 = success, else error                           */
212/* Parameters:  data(I) - pointer to data from ioctl call                   */
213/*                                                                          */
214/* Add a new data node to a lookup structure.  First, check to see if the   */
215/* parent structure refered to by name exists and if it does, then go on to */
216/* add a node to it.                                                        */
217/* ------------------------------------------------------------------------ */
218static int iplookup_addnode(data, ifs)
219caddr_t data;
220ipf_stack_t *ifs;
221{
222	ip_pool_node_t node, *m;
223	iplookupop_t op;
224	iphtable_t *iph;
225	iphtent_t hte;
226	ip_pool_t *p;
227	int err;
228
229	err = 0;
230	BCOPYIN(data, &op, sizeof(op));
231	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
232
233	switch (op.iplo_type)
234	{
235	case IPLT_POOL :
236		if (op.iplo_size != sizeof(node))
237			return EINVAL;
238
239		err = COPYIN(op.iplo_struct, &node, sizeof(node));
240		if (err != 0)
241			return EFAULT;
242
243		p = ip_pool_find(op.iplo_unit, op.iplo_name, ifs);
244		if (p == NULL)
245			return ESRCH;
246
247		/*
248		 * add an entry to a pool - return an error if it already
249		 * exists remove an entry from a pool - if it exists
250		 * - in both cases, the pool *must* exist!
251		 */
252		m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
253		if (m)
254			return EEXIST;
255		err = ip_pool_insert(p, &node.ipn_addr,
256				     &node.ipn_mask, node.ipn_info, ifs);
257		break;
258
259	case IPLT_HASH :
260		if (op.iplo_size != sizeof(hte))
261			return EINVAL;
262
263		err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
264		if (err != 0)
265			return EFAULT;
266
267		iph = fr_findhtable(op.iplo_unit, op.iplo_name, ifs);
268		if (iph == NULL)
269			return ESRCH;
270		err = fr_addhtent(iph, &hte, ifs);
271		break;
272
273	default :
274		err = EINVAL;
275		break;
276	}
277	return err;
278}
279
280
281/* ------------------------------------------------------------------------ */
282/* Function:    iplookup_delnode                                            */
283/* Returns:     int     - 0 = success, else error                           */
284/* Parameters:  data(I) - pointer to data from ioctl call                   */
285/*                                                                          */
286/* Delete a node from a lookup table by first looking for the table it is   */
287/* in and then deleting the entry that gets found.                          */
288/* ------------------------------------------------------------------------ */
289static int iplookup_delnode(data, ifs)
290caddr_t data;
291ipf_stack_t *ifs;
292{
293	ip_pool_node_t node, *m;
294	iplookupop_t op;
295	iphtable_t *iph;
296	iphtent_t hte;
297	ip_pool_t *p;
298	int err;
299
300	err = 0;
301	BCOPYIN(data, &op, sizeof(op));
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, ifs);
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, ifs);
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, ifs);
334		if (iph == NULL)
335			return ESRCH;
336		err = fr_delhtent(iph, &hte, ifs);
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/* ------------------------------------------------------------------------ */
355static int iplookup_addtable(data, ifs)
356caddr_t data;
357ipf_stack_t *ifs;
358{
359	iplookupop_t op;
360	int err;
361
362	err = 0;
363	BCOPYIN(data, &op, sizeof(op));
364
365	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
366
367	switch (op.iplo_type)
368	{
369	case IPLT_POOL :
370		if (ip_pool_find(op.iplo_unit, op.iplo_name, ifs) != NULL)
371			err = EEXIST;
372		else
373			err = ip_pool_create(&op, ifs);
374		break;
375
376	case IPLT_HASH :
377		if (fr_findhtable(op.iplo_unit, op.iplo_name, ifs) != NULL)
378			err = EEXIST;
379		else
380			err = fr_newhtable(&op, ifs);
381		break;
382
383	default :
384		err = EINVAL;
385		break;
386	}
387	return err;
388}
389
390
391/* ------------------------------------------------------------------------ */
392/* Function:    iplookup_deltable                                           */
393/* Returns:     int     - 0 = success, else error                           */
394/* Parameters:  data(I) - pointer to data from ioctl call                   */
395/*                                                                          */
396/* Decodes ioctl request to remove a particular hash table or pool and      */
397/* calls the relevant function to do the cleanup.                           */
398/* ------------------------------------------------------------------------ */
399static int iplookup_deltable(data, ifs)
400caddr_t data;
401ipf_stack_t *ifs;
402{
403	iplookupop_t op;
404	int err;
405
406	BCOPYIN(data, &op, sizeof(op));
407	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
408
409	if (op.iplo_arg & IPLT_ANON)
410		op.iplo_arg &= IPLT_ANON;
411
412	/*
413	 * create a new pool - fail if one already exists with
414	 * the same #
415	 */
416	switch (op.iplo_type)
417	{
418	case IPLT_POOL :
419		err = ip_pool_destroy(&op, ifs);
420		break;
421
422	case IPLT_HASH :
423		err = fr_removehtable(&op, ifs);
424		break;
425
426	default :
427		err = EINVAL;
428		break;
429	}
430	return err;
431}
432
433
434/* ------------------------------------------------------------------------ */
435/* Function:    iplookup_stats                                              */
436/* Returns:     int     - 0 = success, else error                           */
437/* Parameters:  data(I) - pointer to data from ioctl call                   */
438/*                                                                          */
439/* Copy statistical information from inside the kernel back to user space.  */
440/* ------------------------------------------------------------------------ */
441static int iplookup_stats(data, ifs)
442caddr_t data;
443ipf_stack_t *ifs;
444{
445	iplookupop_t op;
446	int err;
447
448	err = 0;
449	BCOPYIN(data, &op, sizeof(op));
450
451	switch (op.iplo_type)
452	{
453	case IPLT_POOL :
454		err = ip_pool_statistics(&op, ifs);
455		break;
456
457	case IPLT_HASH :
458		err = fr_gethtablestat(&op, ifs);
459		break;
460
461	default :
462		err = EINVAL;
463		break;
464	}
465	return err;
466}
467
468
469/* ------------------------------------------------------------------------ */
470/* Function:    iplookup_flush                                              */
471/* Returns:     int     - 0 = success, else error                           */
472/* Parameters:  data(I) - pointer to data from ioctl call                   */
473/*                                                                          */
474/* A flush is called when we want to flush all the nodes from a particular  */
475/* entry in the hash table/pool or want to remove all groups from those.    */
476/* ------------------------------------------------------------------------ */
477static int iplookup_flush(data, ifs)
478caddr_t data;
479ipf_stack_t *ifs;
480{
481	int err, unit, num, type;
482	iplookupflush_t flush;
483
484	err = 0;
485	BCOPYIN(data, &flush, sizeof(flush));
486
487	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
488
489	unit = flush.iplf_unit;
490	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
491		return EINVAL;
492
493	type = flush.iplf_type;
494	err = EINVAL;
495	num = 0;
496
497	if (type == IPLT_POOL || type == IPLT_ALL) {
498		err = 0;
499		num = ip_pool_flush(&flush, ifs);
500	}
501
502	if (type == IPLT_HASH  || type == IPLT_ALL) {
503		err = 0;
504		num += fr_flushhtable(&flush, ifs);
505	}
506
507	if (err == 0) {
508		flush.iplf_count = num;
509		err = COPYOUT(&flush, data, sizeof(flush));
510	}
511	return err;
512}
513
514
515
516void ip_lookup_deref(type, ptr, ifs)
517int type;
518void *ptr;
519ipf_stack_t *ifs;
520{
521	if (ptr == NULL)
522		return;
523
524	WRITE_ENTER(&ifs->ifs_ip_poolrw);
525	switch (type)
526	{
527	case IPLT_POOL :
528		ip_pool_deref(ptr, ifs);
529		break;
530
531	case IPLT_HASH :
532		fr_derefhtable(ptr, ifs);
533		break;
534	}
535	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
536}
537
538
539int ip_lookup_iterate(data, uid, ctx, ifs)
540void *data;
541int uid;
542void *ctx;
543ipf_stack_t *ifs;
544{
545	ipflookupiter_t iter;
546	ipftoken_t *token;
547	int err;
548
549	err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
550	if (err != 0) {
551#ifdef _KERNEL
552		(void) printf("fr_inobj\n");
553#endif
554		return err;
555	}
556
557	if (iter.ili_unit < 0 || iter.ili_unit > IPL_LOGMAX) {
558#ifdef _KERNEL
559		(void) printf("unit=%d\n", iter.ili_unit);
560#endif
561		return EINVAL;
562	}
563
564	if (iter.ili_ival != IPFGENITER_LOOKUP) {
565#ifdef _KERNEL
566		(void) printf("ival=%d\n", iter.ili_ival);
567#endif
568		return EINVAL;
569	}
570
571	token = ipf_findtoken(iter.ili_key, uid, ctx, ifs);
572	if (token == NULL) {
573		RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
574		return ESRCH;
575	}
576
577	switch (iter.ili_type)
578	{
579	case IPLT_POOL :
580		err = ip_pool_getnext(token, &iter, ifs);
581		break;
582	case IPLT_HASH :
583		err = fr_htable_getnext(token, &iter, ifs);
584		break;
585	default :
586#ifdef _KERNEL
587		(void) printf("type=%d\n", iter.ili_type);
588#endif
589		err = EINVAL;
590		break;
591	}
592	RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
593
594	return err;
595}
596
597
598void ip_lookup_iterderef(type, data, ifs)
599u_32_t type;
600void *data;
601ipf_stack_t *ifs;
602{
603	iplookupiterkey_t	key;
604
605	key.ilik_key = type;
606
607	if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
608		return;
609
610	switch (key.ilik_unstr.ilik_type)
611	{
612	case IPLT_HASH :
613		fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
614				    (int)key.ilik_unstr.ilik_unit, data, ifs);
615		break;
616	case IPLT_POOL :
617		ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
618				  (int)key.ilik_unstr.ilik_unit, data, ifs);
619		break;
620	}
621}
622
623
624#else /* IPFILTER_LOOKUP */
625
626/*ARGSUSED*/
627int ip_lookup_ioctl(data, cmd, mode, uid, ifs)
628caddr_t data;
629ioctlcmd_t cmd;
630int mode, uid;
631ipf_stack_t *ifs;
632{
633	return EIO;
634}
635#endif /* IPFILTER_LOOKUP */
636