All of lore.kernel.org
 help / color / mirror / Atom feed
From: Massimiliano Hofer <max@nucleus.it>
To: netfilter-devel@lists.netfilter.org
Subject: Re: [PATCH] entry_data
Date: Mon, 12 Jun 2006 01:19:15 +0200	[thread overview]
Message-ID: <200606120119.16503.max@nucleus.it> (raw)
In-Reply-To: <200606050029.08602.max@nucleus.it>

[-- Attachment #1: Type: text/plain, Size: 665 bytes --]

Hi,
an API isn't worth much if nobody uses it. :)
Here is an example of a module that takes advantage of the patch in my 
previous post.

It is a new version of xt_condition ported to 2.6.17-rc6 with entry_data. Just 
install the regular patchlet and substitute net/netfilter/xt_condition.c with 
the attacched source.

The advantages gained thanks to entry_data are that now match() and destroy() 
are O(1). The overall code is shorter and, IMHO, clearer.

WARNING: this version of condition is still experimental. It worked in my 
preliminary tests, but I will release a more reliable version as soon as 
2.6.17 becomes stable.

-- 
Saluti,
   Massimiliano Hofer

[-- Attachment #2: xt_condition.c --]
[-- Type: text/plain, Size: 8411 bytes --]

/*-------------------------------------------*\
|          Netfilter Condition Module         |
|                                             |
|  Description: This module allows firewall   |
|    rules to match using condition variables |
|    stored in /proc files.                   |
|                                             |
|  Author: Stephane Ouellette     2002-10-22  |
|          <ouellettes@videotron.ca>          |
|          Massimiliano Hofer     2006-05-15  |
|          <max@nucleus.it>                   |
|                                             |
|  History:                                   |
|    2003-02-10  Second version with improved |
|                locking and simplified code. |
|    2006-05-15  2.6.16 adaptations.          |
|                Locking overhaul.            |
|                Various bug fixes.           |
|                                             |
|  This software is distributed under the     |
|  terms of the GNU GPL.                      |
\*-------------------------------------------*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <asm/semaphore.h>
#include <linux/string.h>
#include <linux/list.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_condition.h>

#ifndef CONFIG_PROC_FS
#error  "Proc file system support is required for this module"
#endif

/* Defaults, these can be overridden on the module command-line. */
static unsigned int condition_list_perms = 0644;
static unsigned int compat_dir_name = 0;
static unsigned int condition_uid_perms = 0;
static unsigned int condition_gid_perms = 0;

MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca> and Massimiliano Hofer <max@nucleus.it>");
MODULE_DESCRIPTION("Allows rules to match against condition variables");
MODULE_LICENSE("GPL");
module_param(condition_list_perms, uint, 0600);
MODULE_PARM_DESC(condition_list_perms,"permissions on /proc/net/nf_condition/* files");
module_param(condition_uid_perms, uint, 0600);
MODULE_PARM_DESC(condition_uid_perms,"user owner of /proc/net/nf_condition/* files");
module_param(condition_gid_perms, uint, 0600);
MODULE_PARM_DESC(condition_gid_perms,"group owner of /proc/net/nf_condition/* files");
module_param(compat_dir_name, bool, 0400);
MODULE_PARM_DESC(compat_dir_name,"use old style /proc/net/ipt_condition/* files");
MODULE_ALIAS("ipt_condition");
MODULE_ALIAS("ip6t_condition");

struct condition_variable {
	struct list_head list;
	struct proc_dir_entry *status_proc;
	unsigned int refcount;
        int enabled;   /* TRUE == 1, FALSE == 0 */
};

/* proc_lock is a user context only semaphore used for write access */
/*           to the conditions' list.                               */
static DECLARE_MUTEX(proc_lock);

static LIST_HEAD(conditions_list);
static struct proc_dir_entry *proc_net_condition = NULL;
static const char *dir_name;

static int
xt_condition_read_info(char __user *buffer, char **start, off_t offset,
			int length, int *eof, void *data)
{
	struct condition_variable *var =
	    (struct condition_variable *) data;

	buffer[0] = (var->enabled) ? '1' : '0';
	buffer[1] = '\n';
	if (length>=2)
		*eof = 1;

	return 2;
}


static int
xt_condition_write_info(struct file *file, const char __user *buffer,
			 unsigned long length, void *data)
{
	struct condition_variable *var =
	    (struct condition_variable *) data;
	char newval;

	if (length>0) {
		if (get_user(newval, buffer))
			return -EFAULT;
	        /* Match only on the first character */
		switch (newval) {
		case '0':
			var->enabled = 0;
			break;
		case '1':
			var->enabled = 1;
			break;
		}
	}

	return (int) length;
}


static int
match(const struct sk_buff *skb, const struct net_device *in,
      const struct net_device *out, const struct xt_match *match,
      const void *matchinfo, int offset,
      unsigned int protoff, int *hotdrop, void *entry_data)
{
	const struct condition_info *info =
		(const struct condition_info *) matchinfo;
	struct condition_variable *var=
		(struct condition_variable *)entry_data;

	return var->enabled ^ info->invert;
}



static int
checkentry(const char *tablename, const void *ip,
	   const struct xt_match *match,
	   void *matchinfo, unsigned int matchsize,
	   unsigned int hook_mask, void **entry_data)
{
	static const char * const forbidden_names[]={ "", ".", ".." };
	struct condition_info *info = (struct condition_info *) matchinfo;
	struct list_head *pos;
	struct condition_variable *var, *newvar;
	int i;

	/* We don't want a '/' in a proc file name. */
	for (i=0; i < CONDITION_NAME_LEN && info->name[i] != '\0'; i++)
		if (info->name[i] == '/')
			return 0;
	/* We can't handle file names longer than CONDITION_NAME_LEN and */
	/* we want a NULL terminated string. */
	if (i == CONDITION_NAME_LEN)
		return 0;

	/* We don't want certain reserved names. */
	for (i=0; i < sizeof(forbidden_names)/sizeof(char *); i++)
		if(strcmp(info->name, forbidden_names[i])==0)
			return 0;

	/* Let's acquire the lock, check for the condition and add it */
	/* or increase the reference counter.                         */
	if (down_interruptible(&proc_lock))
	   return -EINTR;

	list_for_each(pos, &conditions_list) {
		var = list_entry(pos, struct condition_variable, list);
		if (strcmp(info->name, var->status_proc->name) == 0) {
			var->refcount++;
			*entry_data=(void *)var;
			up(&proc_lock);
			return 1;
		}
	}

	/* At this point, we need to allocate a new condition variable. */
	newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);

	if (!newvar) {
		up(&proc_lock);
		return -ENOMEM;
	}

	/* Create the condition variable's proc file entry. */
	newvar->status_proc = create_proc_entry(info->name, condition_list_perms, proc_net_condition);

	if (!newvar->status_proc) {
		kfree(newvar);
		up(&proc_lock);
		return -ENOMEM;
	}

	newvar->refcount = 1;
	newvar->enabled = 0;
	newvar->status_proc->owner = THIS_MODULE;
	newvar->status_proc->data = newvar;
	wmb();
	newvar->status_proc->read_proc = xt_condition_read_info;
	newvar->status_proc->write_proc = xt_condition_write_info;

	list_add_rcu(&newvar->list, &conditions_list);

	newvar->status_proc->uid = condition_uid_perms;
	newvar->status_proc->gid = condition_gid_perms;

	up(&proc_lock);

	*entry_data=(void *)newvar;

	return 1;
}


static void
destroy(const struct xt_match *match, void *matchinfo,
	unsigned int matchsize, void *entry_data)
{
	struct condition_info *info = (struct condition_info *) matchinfo;
	struct condition_variable *var=
		(struct condition_variable *)entry_data;

	BUG_ON(entry_data==NULL);

	down(&proc_lock);

	if (--var->refcount == 0) {
		list_del_rcu(&var->list);
		remove_proc_entry(var->status_proc->name, proc_net_condition);
		up(&proc_lock);
		/* synchronize_rcu() would be goog enough, but synchronize_net() */
		/* guarantees that no packet will go out with the old rule after */
		/* succesful removal.                                            */
		synchronize_net();
		kfree(var);
		return;
	}

	up(&proc_lock);
}


static struct xt_match condition_match = {
	.name = "condition",
	.family = AF_INET,
	.matchsize = sizeof(struct condition_info),
	.match = &match,
	.checkentry = &checkentry,
	.destroy = &destroy,
	.me = THIS_MODULE
};

static struct xt_match condition6_match = {
	.name = "condition",
	.family = AF_INET,
	.matchsize = sizeof(struct condition_info),
	.match = &match,
	.checkentry = &checkentry,
	.destroy = &destroy,
	.me = THIS_MODULE
};

static int __init
init(void)
{
	int errorcode;

	dir_name = compat_dir_name? "ipt_condition": "nf_condition";

	proc_net_condition = proc_mkdir(dir_name, proc_net);
	if (!proc_net_condition) {
		remove_proc_entry(dir_name, proc_net);
		return -EACCES;
	}

        errorcode = xt_register_match(&condition_match);
	if (errorcode) {
		xt_unregister_match(&condition_match);
		remove_proc_entry(dir_name, proc_net);
		return errorcode;
	}

	errorcode = xt_register_match(&condition6_match);
	if (errorcode) {
		xt_unregister_match(&condition6_match);
		xt_unregister_match(&condition_match);
		remove_proc_entry(dir_name, proc_net);
		return errorcode;
	}

	return 0;
}


static void __exit
fini(void)
{
	xt_unregister_match(&condition6_match);
	xt_unregister_match(&condition_match);
	remove_proc_entry(dir_name, proc_net);
}

module_init(init);
module_exit(fini);

  reply	other threads:[~2006-06-11 23:19 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-04 22:29 [PATCH] entry_data Massimiliano Hofer
2006-06-11 23:19 ` Massimiliano Hofer [this message]
2006-06-12  9:50   ` Pablo Neira Ayuso
2006-06-12 12:45     ` Massimiliano Hofer
2006-06-13 15:19       ` Pablo Neira Ayuso
2006-06-13 20:56         ` Massimiliano Hofer
2006-06-19  0:15           ` Pablo Neira Ayuso
2006-06-19  7:02             ` Massimiliano Hofer
2006-06-19 23:37               ` Pablo Neira Ayuso
2006-06-20  1:39                 ` Patrick McHardy
2006-06-14  9:03 ` Sven Anders
2006-06-17 22:55   ` Massimiliano Hofer
2006-06-19 17:45     ` Patrick McHardy
2006-06-19 23:05       ` Massimiliano Hofer
2006-06-20  1:29         ` Patrick McHardy
2006-06-19 17:34   ` Patrick McHardy
2006-06-19 22:35     ` Massimiliano Hofer
2006-06-19 23:13       ` Patrick McHardy
2006-06-20 11:25         ` Massimiliano Hofer
2006-06-20 13:17           ` Patrick McHardy
2006-06-21  0:03             ` [PATCH] priv_data (formerly entry_data) Massimiliano Hofer
2006-06-21  0:30               ` Patrick McHardy
2006-06-21  0:45                 ` Massimiliano Hofer
2006-06-21  1:04                   ` Patrick McHardy
2006-06-21  8:31                     ` Massimiliano Hofer
2006-06-21 23:50                 ` Massimiliano Hofer
2006-06-22 15:18                   ` Patrick McHardy
2006-06-21  0:33               ` Massimiliano Hofer
2006-06-21  0:42                 ` Massimiliano Hofer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200606120119.16503.max@nucleus.it \
    --to=max@nucleus.it \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.