nf_log.c 3.6 KB
Newer Older
1 2 3 4 5 6
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
7
#include <linux/seq_file.h>
8 9 10 11 12 13 14 15 16 17 18 19
#include <net/protocol.h>

#include "nf_internals.h"

/* Internal logging interface, which relies on the real 
   LOG target modules */

#define NF_LOG_PREFIXLEN		128

static struct nf_logger *nf_logging[NPROTO]; /* = NULL */
static DEFINE_SPINLOCK(nf_log_lock);

20 21
/* return EBUSY if somebody else is registered, EEXIST if the same logger
 * is registred, 0 on success. */
22 23 24 25
int nf_log_register(int pf, struct nf_logger *logger)
{
	int ret = -EBUSY;

26 27 28
	if (pf >= NPROTO)
		return -EINVAL;

29 30 31 32 33 34
	/* Any setup of logging members must be done before
	 * substituting pointer. */
	spin_lock(&nf_log_lock);
	if (!nf_logging[pf]) {
		rcu_assign_pointer(nf_logging[pf], logger);
		ret = 0;
35 36 37
	} else if (nf_logging[pf] == logger)
		ret = -EEXIST;

38 39 40 41 42
	spin_unlock(&nf_log_lock);
	return ret;
}		
EXPORT_SYMBOL(nf_log_register);

43
int nf_log_unregister_pf(int pf)
44
{
45 46 47
	if (pf >= NPROTO)
		return -EINVAL;

48 49 50 51 52 53
	spin_lock(&nf_log_lock);
	nf_logging[pf] = NULL;
	spin_unlock(&nf_log_lock);

	/* Give time to concurrent readers. */
	synchronize_net();
54 55

	return 0;
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
}
EXPORT_SYMBOL(nf_log_unregister_pf);

void nf_log_unregister_logger(struct nf_logger *logger)
{
	int i;

	spin_lock(&nf_log_lock);
	for (i = 0; i < NPROTO; i++) {
		if (nf_logging[i] == logger)
			nf_logging[i] = NULL;
	}
	spin_unlock(&nf_log_lock);

	synchronize_net();
}
EXPORT_SYMBOL(nf_log_unregister_logger);

void nf_log_packet(int pf,
		   unsigned int hooknum,
		   const struct sk_buff *skb,
		   const struct net_device *in,
		   const struct net_device *out,
		   struct nf_loginfo *loginfo,
		   const char *fmt, ...)
{
	va_list args;
	char prefix[NF_LOG_PREFIXLEN];
	struct nf_logger *logger;
	
	rcu_read_lock();
	logger = rcu_dereference(nf_logging[pf]);
	if (logger) {
		va_start(args, fmt);
		vsnprintf(prefix, sizeof(prefix), fmt, args);
		va_end(args);
		/* We must read logging before nf_logfn[pf] */
		logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
	} else if (net_ratelimit()) {
		printk(KERN_WARNING "nf_log_packet: can\'t log since "
		       "no backend logging module loaded in! Please either "
		       "load one, or disable logging explicitly\n");
	}
	rcu_read_unlock();
}
EXPORT_SYMBOL(nf_log_packet);

#ifdef CONFIG_PROC_FS
static void *seq_start(struct seq_file *seq, loff_t *pos)
{
	rcu_read_lock();

	if (*pos >= NPROTO)
		return NULL;

	return pos;
}

static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	(*pos)++;

	if (*pos >= NPROTO)
		return NULL;

	return pos;
}

static void seq_stop(struct seq_file *s, void *v)
{
	rcu_read_unlock();
}

static int seq_show(struct seq_file *s, void *v)
{
	loff_t *pos = v;
	const struct nf_logger *logger;

	logger = rcu_dereference(nf_logging[*pos]);

	if (!logger)
		return seq_printf(s, "%2lld NONE\n", *pos);
	
	return seq_printf(s, "%2lld %s\n", *pos, logger->name);
}

static struct seq_operations nflog_seq_ops = {
	.start	= seq_start,
	.next	= seq_next,
	.stop	= seq_stop,
	.show	= seq_show,
};

static int nflog_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &nflog_seq_ops);
}

static struct file_operations nflog_file_ops = {
	.owner	 = THIS_MODULE,
	.open	 = nflog_open,
	.read	 = seq_read,
	.llseek	 = seq_lseek,
	.release = seq_release,
};

#endif /* PROC_FS */


int __init netfilter_log_init(void)
{
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry *pde;
169

170 171 172 173 174
	pde = create_proc_entry("nf_log", S_IRUGO, proc_net_netfilter);
	if (!pde)
		return -1;

	pde->proc_fops = &nflog_file_ops;
175
#endif
176 177
	return 0;
}