[PATCH 1/2] Netfilter: xt_LOG: Implement ring buffer support
From: Richard Weinberger
Date: Wed Feb 15 2012 - 18:28:14 EST
This patch introduces NETFILTER_XT_TARGET_LOG_RING.
It allows logging into various ring buffers which are
represented as pipe-like files in /proc/net/netfilter/xt_LOG_ring/.
Signed-off-by: Richard Weinberger <richard@xxxxxx>
---
include/linux/netfilter/xt_LOG.h | 12 +-
include/net/netfilter/nf_log.h | 1 +
include/net/netfilter/xt_log.h | 22 ++
net/netfilter/Kconfig | 13 +
net/netfilter/xt_LOG.c | 631 ++++++++++++++++++++++++++++++++++++-
5 files changed, 660 insertions(+), 19 deletions(-)
diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h
index cac0790..e4b1177 100644
--- a/include/linux/netfilter/xt_LOG.h
+++ b/include/linux/netfilter/xt_LOG.h
@@ -8,7 +8,7 @@
#define XT_LOG_UID 0x08 /* Log UID owning local socket */
#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */
-#define XT_LOG_MASK 0x2f
+#define XT_LOG_MASK 0x6f
struct xt_log_info {
unsigned char level;
@@ -16,4 +16,14 @@ struct xt_log_info {
char prefix[30];
};
+struct xt_log_info_v1 {
+ unsigned char level;
+ unsigned char logflags;
+ char prefix[30];
+
+ char ring_name[30];
+ __aligned_u64 ring_size;
+ struct xt_LOG_ring_ctx *rctx __attribute__((aligned(8)));
+};
+
#endif /* _XT_LOG_H */
diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h
index e991bd0..18a94f9 100644
--- a/include/net/netfilter/nf_log.h
+++ b/include/net/netfilter/nf_log.h
@@ -14,6 +14,7 @@
#define NF_LOG_TYPE_LOG 0x01
#define NF_LOG_TYPE_ULOG 0x02
+#define NF_LOG_TYPE_RING 0x04
struct nf_loginfo {
u_int8_t type;
diff --git a/include/net/netfilter/xt_log.h b/include/net/netfilter/xt_log.h
index 767e08d..c9a3718 100644
--- a/include/net/netfilter/xt_log.h
+++ b/include/net/netfilter/xt_log.h
@@ -55,3 +55,25 @@ static void __sb_close(struct sbuff *m, int print)
}
#define sb_close(m) __sb_close(m, 1)
+
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+struct xt_LOG_ring_ctx;
+struct xt_LOG_ring_ctx *xt_LOG_ring_new_ctx(const char *name, size_t rb_size);
+int xt_LOG_ring_add_record(const struct xt_LOG_ring_ctx *rctx, const char *buf, \
+ unsigned int len);
+void xt_LOG_ring_get(struct xt_LOG_ring_ctx *ctx);
+void xt_LOG_ring_put(struct xt_LOG_ring_ctx *ctx);
+struct xt_LOG_ring_ctx *xt_LOG_ring_find_ctx(const char *name);
+
+void xt_LOG_ring_exit(void);
+int xt_LOG_ring_init(void);
+#else
+static inline void xt_LOG_ring_exit(void)
+{
+}
+
+static inline int xt_LOG_ring_init(void)
+{
+ return 0;
+}
+#endif
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index b895d8b..ac62599 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -533,6 +533,19 @@ config NETFILTER_XT_TARGET_LOG
To compile it as a module, choose M here. If unsure, say N.
+if NETFILTER_XT_TARGET_LOG
+
+config NETFILTER_XT_TARGET_LOG_RING
+ bool 'Ring buffer support'
+ default y
+ select RING_BUFFER
+ help
+ Using this it is possible to record packets into one or more ring buffers
+ instead of the kernel syslog.
+ Each ring buffer is represented as file in /proc/net/netfilter/xt_LOG_ring/.
+
+endif
+
config NETFILTER_XT_TARGET_MARK
tristate '"MARK" target support'
depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c
index 1595608..211d341 100644
--- a/net/netfilter/xt_LOG.c
+++ b/net/netfilter/xt_LOG.c
@@ -16,6 +16,21 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
+#include <linux/ctype.h>
+#include <linux/ring_buffer.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <net/ipv6.h>
#include <net/icmp.h>
#include <net/udp.h>
@@ -29,6 +44,44 @@
#include <net/netfilter/nf_log.h>
#include <net/netfilter/xt_log.h>
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+#define RING_DIR "xt_LOG_ring"
+
+struct xt_LOG_ring_ctx {
+ char name[32];
+ struct ring_buffer *buffer;
+ atomic_t pipe_in_use;
+ atomic_t refcnt;
+
+ struct list_head list;
+};
+
+struct rlog_entry {
+ size_t count;
+ char msg[0];
+};
+
+struct rlog_iter {
+ struct ring_buffer *buffer;
+ const char *buffer_name;
+ struct rlog_entry *ent;
+
+ char print_buf[PAGE_SIZE];
+ size_t print_buf_len;
+ size_t print_buf_pos;
+
+ unsigned long lost_events;
+ int cpu;
+
+ struct mutex lock;
+};
+
+static DEFINE_SPINLOCK(ring_list_lock);
+static LIST_HEAD(ring_list);
+static DECLARE_WAIT_QUEUE_HEAD(rlog_wait);
+static struct proc_dir_entry *prlog;
+#endif
+
static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
@@ -155,7 +208,7 @@ static void dump_ipv4_packet(struct sbuff *m,
const struct iphdr *ih;
unsigned int logflags;
- if (info->type == NF_LOG_TYPE_LOG)
+ if (info->type == NF_LOG_TYPE_LOG || info->type == NF_LOG_TYPE_RING)
logflags = info->u.log.logflags;
else
logflags = NF_LOG_MASK;
@@ -394,7 +447,7 @@ static void dump_ipv4_mac_header(struct sbuff *m,
struct net_device *dev = skb->dev;
unsigned int logflags = 0;
- if (info->type == NF_LOG_TYPE_LOG)
+ if (info->type == NF_LOG_TYPE_LOG || info->type == NF_LOG_TYPE_RING)
logflags = info->u.log.logflags;
if (!(logflags & XT_LOG_MACDECODE))
@@ -434,9 +487,10 @@ log_packet_common(struct sbuff *m,
const struct nf_loginfo *loginfo,
const char *prefix)
{
- sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
- prefix,
- in ? in->name : "",
+ if (loginfo->type == NF_LOG_TYPE_LOG)
+ sb_add(m, "<%d>", loginfo->u.log.level);
+
+ sb_add(m, "%sIN=%s OUT=%s ", prefix, in ? in->name : "",
out ? out->name : "");
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge) {
@@ -454,8 +508,7 @@ log_packet_common(struct sbuff *m,
}
-static void
-ipt_log_packet(u_int8_t pf,
+static struct sbuff *ipt_log_packet(u_int8_t pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
@@ -475,6 +528,19 @@ ipt_log_packet(u_int8_t pf,
dump_ipv4_packet(m, loginfo, skb, 0);
+ return m;
+}
+
+static void ipt_log_packet_logger(u_int8_t pf,
+ unsigned int hooknum,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct nf_loginfo *loginfo,
+ const char *prefix)
+{
+ struct sbuff *m = ipt_log_packet(pf, hooknum, skb, in, out, loginfo, prefix);
+
sb_close(m);
}
@@ -493,7 +559,7 @@ static void dump_ipv6_packet(struct sbuff *m,
unsigned int hdrlen = 0;
unsigned int logflags;
- if (info->type == NF_LOG_TYPE_LOG)
+ if (info->type == NF_LOG_TYPE_LOG || info->type == NF_LOG_TYPE_RING)
logflags = info->u.log.logflags;
else
logflags = NF_LOG_MASK;
@@ -734,7 +800,7 @@ static void dump_ipv6_mac_header(struct sbuff *m,
struct net_device *dev = skb->dev;
unsigned int logflags = 0;
- if (info->type == NF_LOG_TYPE_LOG)
+ if (info->type == NF_LOG_TYPE_LOG || info->type == NF_LOG_TYPE_RING)
logflags = info->u.log.logflags;
if (!(logflags & XT_LOG_MACDECODE))
@@ -782,8 +848,7 @@ fallback:
sb_add(m, " ");
}
-static void
-ip6t_log_packet(u_int8_t pf,
+static struct sbuff *ip6t_log_packet(u_int8_t pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
@@ -803,6 +868,19 @@ ip6t_log_packet(u_int8_t pf,
dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1);
+ return m;
+}
+
+static void ip6t_log_packet_logger(u_int8_t pf,
+ unsigned int hooknum,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct nf_loginfo *loginfo,
+ const char *prefix)
+{
+ struct sbuff *m = ip6t_log_packet(pf, hooknum, skb, in, out, loginfo, prefix);
+
sb_close(m);
}
#endif
@@ -812,22 +890,28 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_log_info *loginfo = par->targinfo;
struct nf_loginfo li;
+ struct sbuff *m;
li.type = NF_LOG_TYPE_LOG;
li.u.log.level = loginfo->level;
li.u.log.logflags = loginfo->logflags;
if (par->family == NFPROTO_IPV4)
- ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
- par->out, &li, loginfo->prefix);
+ m = ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
+ par->out, &li, loginfo->prefix);
#if IS_ENABLED(CONFIG_IPV6)
else if (par->family == NFPROTO_IPV6)
- ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
- par->out, &li, loginfo->prefix);
+ m = ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
+ par->out, &li, loginfo->prefix);
#endif
- else
+ else {
WARN_ON_ONCE(1);
+ goto out;
+ }
+ sb_close(m);
+
+out:
return XT_CONTINUE;
}
@@ -851,37 +935,542 @@ static int log_tg_check(const struct xt_tgchk_param *par)
return 0;
}
+static unsigned int
+log_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_log_info_v1 *loginfo = par->targinfo;
+ struct nf_loginfo li;
+ struct sbuff *m;
+
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+ if (loginfo->ring_size)
+ li.type = NF_LOG_TYPE_RING;
+ else
+#endif
+ li.type = NF_LOG_TYPE_LOG;
+
+ li.u.log.level = loginfo->level;
+ li.u.log.logflags = loginfo->logflags;
+
+ if (par->family == NFPROTO_IPV4)
+ m = ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
+ par->out, &li, loginfo->prefix);
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (par->family == NFPROTO_IPV6)
+ m = ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
+ par->out, &li, loginfo->prefix);
+#endif
+ else {
+ WARN_ON_ONCE(1);
+ goto out;
+ }
+
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+ if (loginfo->ring_size) {
+ sb_add(m, "\n");
+ xt_LOG_ring_add_record(loginfo->rctx, m->buf, m->count);
+ __sb_close(m, 0);
+ } else
+#endif
+ sb_close(m);
+
+out:
+ return XT_CONTINUE;
+}
+
+static int log_tg_check_v1(const struct xt_tgchk_param *par)
+{
+ struct xt_log_info_v1 *loginfo = par->targinfo;
+
+ if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6)
+ return -EINVAL;
+
+ if (loginfo->level >= 8) {
+ pr_debug("level %u >= 8\n", loginfo->level);
+ return -EINVAL;
+ }
+
+ if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
+ pr_debug("prefix is not null-terminated\n");
+ return -EINVAL;
+ }
+
+ /* a non-empty ring_size indicates that we're using ring_buffer */
+ if (loginfo->ring_size) {
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+ int i;
+ struct xt_LOG_ring_ctx *rctx;
+
+ if (loginfo->ring_name[sizeof(loginfo->ring_name)-1] != '\0') {
+ pr_debug("ring_name is not null-terminated\n");
+ return -EINVAL;
+ }
+
+ if (!loginfo->ring_name[0]) {
+ pr_debug("ring_name is empty\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < strlen(loginfo->ring_name); i++) {
+ if (!isalnum(loginfo->ring_name[i])) {
+ pr_debug("ring_name contains "
+ "a non-alphanumeric character\n");
+ return -EINVAL;
+ }
+ }
+
+ rctx = xt_LOG_ring_find_ctx(loginfo->ring_name);
+ if (!rctx) {
+ rctx = xt_LOG_ring_new_ctx(loginfo->ring_name,
+ loginfo->ring_size);
+ if (IS_ERR(rctx))
+ return PTR_ERR(rctx);
+ }
+
+ xt_LOG_ring_get(rctx);
+ loginfo->rctx = rctx;
+#else
+ pr_debug("Sorry, this kernel was built without CONFIG_NETFILTER_XT_TARGET_LOG_RING\n");
+ return -EINVAL;
+#endif
+ }
+
+ return 0;
+}
+
+static void log_tg_destroy_v1(const struct xt_tgdtor_param *par)
+{
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+ const struct xt_log_info_v1 *loginfo = par->targinfo;
+ struct xt_LOG_ring_ctx *rctx = loginfo->rctx;
+
+ if (loginfo->ring_size)
+ xt_LOG_ring_put(rctx);
+#endif
+}
+
+#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING
+static void wakeup_work_handler(struct work_struct *work)
+{
+ wake_up(&rlog_wait);
+}
+
+static DECLARE_WORK(wakeup_work, wakeup_work_handler);
+
+static void rlog_wake_up(void)
+{
+ schedule_work(&wakeup_work);
+}
+
+int xt_LOG_ring_add_record(const struct xt_LOG_ring_ctx *rctx,
+ const char *buf, unsigned int len)
+{
+ struct rlog_entry *entry;
+ struct ring_buffer_event *event;
+
+ event = ring_buffer_lock_reserve(rctx->buffer, sizeof(*entry) + len);
+ if (!event)
+ return 1;
+
+ entry = ring_buffer_event_data(event);
+ memcpy(entry->msg, buf, len);
+ entry->count = len;
+
+ ring_buffer_unlock_commit(rctx->buffer, event);
+ rlog_wake_up();
+
+ return 0;
+}
+
+static struct rlog_entry *peek_next_entry(struct rlog_iter *iter, int cpu,
+ unsigned long long *ts)
+{
+ struct ring_buffer_event *event;
+
+ event = ring_buffer_peek(iter->buffer, cpu, ts, &iter->lost_events);
+
+ if (event)
+ return ring_buffer_event_data(event);
+
+ return NULL;
+}
+
+static struct rlog_entry *find_next_entry(struct rlog_iter *iter)
+{
+ struct rlog_entry *ent, *next = NULL;
+ unsigned long long next_ts = 0, ts;
+ int cpu, next_cpu = -1;
+
+ for_each_buffer_cpu (iter->buffer, cpu) {
+ if (ring_buffer_empty_cpu(iter->buffer, cpu))
+ continue;
+
+ ent = peek_next_entry(iter, cpu, &ts);
+
+ if (ent && (!next || ts < next_ts)) {
+ next = ent;
+ next_cpu = cpu;
+ next_ts = ts;
+ }
+ }
+
+ iter->cpu = next_cpu;
+
+ return next;
+}
+
+static struct rlog_iter *find_next_entry_inc(struct rlog_iter *iter)
+{
+ iter->ent = find_next_entry(iter);
+
+ if (iter->ent)
+ return iter;
+
+ return NULL;
+}
+
+static int buffer_empty(struct rlog_iter *iter)
+{
+ int cpu;
+
+ for_each_buffer_cpu (iter->buffer, cpu) {
+ if (!ring_buffer_empty_cpu(iter->buffer, cpu))
+ return 0;
+ }
+
+ return 1;
+}
+
+static ssize_t rlog_to_user(struct rlog_iter *iter, char __user *ubuf,
+ size_t cnt)
+{
+ int ret;
+ int len;
+
+ if (!cnt)
+ goto out;
+
+ len = iter->print_buf_len - iter->print_buf_pos;
+ if (len < 1)
+ return -EBUSY;
+
+ if (cnt > len)
+ cnt = len;
+
+ ret = copy_to_user(ubuf, iter->print_buf + iter->print_buf_pos, cnt);
+ if (ret == cnt)
+ return -EFAULT;
+
+ cnt -= ret;
+ iter->print_buf_pos += cnt;
+
+out:
+ return cnt;
+}
+
+static int rlog_open_pipe(struct inode *inode, struct file *file)
+{
+ struct rlog_iter *iter;
+ struct xt_LOG_ring_ctx *tgt = PDE(inode)->data;
+ int ret = 0;
+
+ /* only one consuming reader is allowed */
+ if (atomic_cmpxchg(&tgt->pipe_in_use, 0, 1)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+ if (!iter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mutex_init(&iter->lock);
+ iter->buffer = tgt->buffer;
+ iter->buffer_name = tgt->name;
+
+ file->private_data = iter;
+out:
+ return ret;
+}
+
+static unsigned int rlog_poll_pipe(struct file *file, poll_table *poll_table)
+{
+ struct rlog_iter *iter = file->private_data;
+
+ if (!buffer_empty(iter))
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &rlog_wait, poll_table);
+
+ if (!buffer_empty(iter))
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int rlog_release_pipe(struct inode *inode, struct file *file)
+{
+ struct rlog_iter *iter = file->private_data;
+ struct xt_LOG_ring_ctx *tgt = PDE(inode)->data;
+
+ mutex_destroy(&iter->lock);
+ kfree(iter);
+ atomic_set(&tgt->pipe_in_use, 0);
+
+ return 0;
+}
+
+static void wait_pipe(struct rlog_iter *iter)
+{
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(&rlog_wait, &wait, TASK_INTERRUPTIBLE);
+
+ if (buffer_empty(iter))
+ schedule();
+
+ finish_wait(&rlog_wait, &wait);
+}
+
+static int rlog_wait_pipe(struct file *file)
+{
+ struct rlog_iter *iter = file->private_data;
+
+ while (buffer_empty(iter)) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ mutex_unlock(&iter->lock);
+
+ wait_pipe(iter);
+
+ mutex_lock(&iter->lock);
+
+ if (signal_pending(current))
+ return -EINTR;
+ }
+
+ return 1;
+}
+
+static ssize_t rlog_read_pipe(struct file *file, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct rlog_iter *iter = file->private_data;
+ ssize_t ret;
+
+ ret = rlog_to_user(iter, ubuf, cnt);
+ if (ret != -EBUSY)
+ goto out;
+
+ iter->print_buf_pos = 0;
+ iter->print_buf_len = 0;
+
+ if (cnt >= PAGE_SIZE)
+ cnt = PAGE_SIZE - 1;
+
+ mutex_lock(&iter->lock);
+again:
+ ret = rlog_wait_pipe(file);
+ if (ret <= 0)
+ goto out_unlock;
+
+ while (find_next_entry_inc(iter) != NULL) {
+ struct rlog_entry *ent;
+ ent = iter->ent;
+
+ if (ent->count >= PAGE_SIZE - iter->print_buf_len)
+ break;
+
+ memcpy(iter->print_buf + iter->print_buf_len, ent->msg,
+ ent->count);
+ iter->print_buf_len += ent->count;
+
+ ring_buffer_consume(iter->buffer, iter->cpu, NULL,
+ &iter->lost_events);
+ if (iter->lost_events)
+ printk(KERN_WARNING KBUILD_MODNAME ": Ring %s "
+ "lost %lu events\n", iter->buffer_name,
+ iter->lost_events);
+
+ if (iter->print_buf_len >= cnt)
+ break;
+ }
+
+ ret = rlog_to_user(iter, ubuf, cnt);
+
+ if (iter->print_buf_pos >= iter->print_buf_len) {
+ iter->print_buf_pos = 0;
+ iter->print_buf_len = 0;
+ }
+
+ if (ret == -EBUSY)
+ goto again;
+out_unlock:
+ mutex_unlock(&iter->lock);
+out:
+ return ret;
+}
+
+static const struct file_operations rlog_pipe_fops = {
+ .open = rlog_open_pipe,
+ .poll = rlog_poll_pipe,
+ .read = rlog_read_pipe,
+ .release = rlog_release_pipe,
+ .llseek = no_llseek,
+};
+
+struct xt_LOG_ring_ctx *xt_LOG_ring_new_ctx(const char *name, size_t rb_size)
+{
+ struct xt_LOG_ring_ctx *new;
+
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ new = ERR_PTR(-ENOMEM);
+
+ goto out;
+ }
+
+ new->buffer = ring_buffer_alloc(rb_size << 10, RB_FL_OVERWRITE);
+ if (!new->buffer) {
+ kfree(new);
+ new = ERR_PTR(-ENOMEM);
+
+ goto out;
+ }
+
+ strlcpy(new->name, name, sizeof new->name);
+
+ if (!proc_create_data(name, 0400, prlog, &rlog_pipe_fops, new)) {
+ ring_buffer_free(new->buffer);
+ kfree(new);
+ new = ERR_PTR(-ENOMEM);
+
+ goto out;
+ }
+
+ atomic_set(&new->pipe_in_use, 0);
+ atomic_set(&new->refcnt, 0);
+
+ spin_lock(&ring_list_lock);
+ list_add(&new->list, &ring_list);
+ spin_unlock(&ring_list_lock);
+out:
+ return new;
+}
+
+static void free_xt_LOG_ring_ctx(struct xt_LOG_ring_ctx *ctx)
+{
+ remove_proc_entry(ctx->name, prlog);
+ ring_buffer_free(ctx->buffer);
+ list_del(&ctx->list);
+ kfree(ctx);
+}
+
+void xt_LOG_ring_get(struct xt_LOG_ring_ctx *ctx)
+{
+ atomic_inc(&ctx->refcnt);
+}
+
+void xt_LOG_ring_put(struct xt_LOG_ring_ctx *ctx)
+{
+ if (atomic_dec_and_test(&ctx->refcnt))
+ free_xt_LOG_ring_ctx(ctx);
+}
+
+struct xt_LOG_ring_ctx *xt_LOG_ring_find_ctx(const char *name)
+{
+ struct list_head *e;
+ struct xt_LOG_ring_ctx *tmp, *victim = NULL;
+
+ spin_lock(&ring_list_lock);
+
+ list_for_each(e, &ring_list) {
+ tmp = list_entry(e, struct xt_LOG_ring_ctx, list);
+ if (strcmp(tmp->name, name) == 0) {
+ victim = tmp;
+
+ goto out;
+ }
+ }
+
+out:
+ spin_unlock(&ring_list_lock);
+
+ return victim;
+}
+
+void __exit xt_LOG_ring_exit(void)
+{
+ WARN_ON(!list_empty(&ring_list));
+ remove_proc_entry(RING_DIR, proc_net_netfilter);
+}
+
+int __init xt_LOG_ring_init(void)
+{
+ prlog = proc_mkdir(RING_DIR, proc_net_netfilter);
+ if (!prlog)
+ return -ENOMEM;
+
+ return 0;
+}
+#endif /* CONFIG_NETFILTER_XT_TARGET_LOG_RING */
+
static struct xt_target log_tg_regs[] __read_mostly = {
{
.name = "LOG",
.family = NFPROTO_IPV4,
+ .revision = 0,
.target = log_tg,
.targetsize = sizeof(struct xt_log_info),
.checkentry = log_tg_check,
.me = THIS_MODULE,
},
+ {
+ .name = "LOG",
+ .family = NFPROTO_IPV4,
+ .revision = 1,
+ .target = log_tg_v1,
+ .targetsize = sizeof(struct xt_log_info_v1),
+ .checkentry = log_tg_check_v1,
+ .destroy = log_tg_destroy_v1,
+ .me = THIS_MODULE,
+ },
#if IS_ENABLED(CONFIG_IPV6)
{
.name = "LOG",
.family = NFPROTO_IPV6,
+ .revision = 0,
.target = log_tg,
.targetsize = sizeof(struct xt_log_info),
.checkentry = log_tg_check,
.me = THIS_MODULE,
},
+ {
+ .name = "LOG",
+ .family = NFPROTO_IPV6,
+ .revision = 1,
+ .target = log_tg_v1,
+ .targetsize = sizeof(struct xt_log_info_v1),
+ .checkentry = log_tg_check_v1,
+ .destroy = log_tg_destroy_v1,
+ .me = THIS_MODULE,
+ },
#endif
};
static struct nf_logger ipt_log_logger __read_mostly = {
.name = "ipt_LOG",
- .logfn = &ipt_log_packet,
+ .logfn = &ipt_log_packet_logger,
.me = THIS_MODULE,
};
#if IS_ENABLED(CONFIG_IPV6)
static struct nf_logger ip6t_log_logger __read_mostly = {
.name = "ip6t_LOG",
- .logfn = &ip6t_log_packet,
+ .logfn = &ip6t_log_packet_logger,
.me = THIS_MODULE,
};
#endif
@@ -890,6 +1479,10 @@ static int __init log_tg_init(void)
{
int ret;
+ ret = xt_LOG_ring_init();
+ if (ret < 0)
+ return ret;
+
ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
if (ret < 0)
return ret;
@@ -908,6 +1501,7 @@ static void __exit log_tg_exit(void)
nf_log_unregister(&ip6t_log_logger);
#endif
xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
+ xt_LOG_ring_exit();
}
module_init(log_tg_init);
@@ -916,6 +1510,7 @@ module_exit(log_tg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@xxxxxxxxxxxxx>");
MODULE_AUTHOR("Jan Rekorajski <baggins@xxxxxxxxxx>");
+MODULE_AUTHOR("Richard Weinberger <richard@xxxxxx>");
MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging");
MODULE_ALIAS("ipt_LOG");
MODULE_ALIAS("ip6t_LOG");
--
1.7.7.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/