From patchwork Thu Feb 9 21:54:53 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 140442 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 18E4BB6EEE for ; Fri, 10 Feb 2012 08:56:28 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758505Ab2BIV4G (ORCPT ); Thu, 9 Feb 2012 16:56:06 -0500 Received: from a.ns.miles-group.at ([95.130.255.143]:47853 "EHLO radon.swed.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758458Ab2BIVzM (ORCPT ); Thu, 9 Feb 2012 16:55:12 -0500 Received: (qmail 28553 invoked by uid 89); 9 Feb 2012 21:55:10 -0000 Received: by simscan 1.3.1 ppid: 28454, pid: 28550, t: 0.1848s scanners: attach: 1.3.1 clamav: 0.96.5/m:53 Received: from unknown (HELO raccoon.haslach.nod.at) (richard@nod.at@212.183.98.209) by radon.swed.at with ESMTPA; 9 Feb 2012 21:55:10 -0000 From: Richard Weinberger To: netfilter-devel@vger.kernel.org Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, eric.dumazet@gmail.com, jengelh@medozas.de, rostedt@goodmis.org, pablo@netfilter.org, Richard Weinberger Subject: [PATCH 4/4] Netfilter: xt_LOG: Implement ring buffer support Date: Thu, 9 Feb 2012 22:54:53 +0100 Message-Id: <1328824493-4136-7-git-send-email-richard@nod.at> X-Mailer: git-send-email 1.7.7.3 In-Reply-To: <1328824493-4136-1-git-send-email-richard@nod.at> References: <1328824493-4136-1-git-send-email-richard@nod.at> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- include/linux/netfilter/xt_LOG.h | 13 +- include/net/netfilter/nf_log.h | 1 + include/net/netfilter/xt_log_ring.h | 24 ++ net/netfilter/Kconfig | 13 + net/netfilter/xt_LOG.c | 642 ++++++++++++++++++++++++++++++++++- 5 files changed, 674 insertions(+), 19 deletions(-) create mode 100644 include/net/netfilter/xt_log_ring.h diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h index cac0790..d84710c 100644 --- a/include/linux/netfilter/xt_LOG.h +++ b/include/linux/netfilter/xt_LOG.h @@ -8,7 +8,8 @@ #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_ADD_TIMESTAMP 0x40 /* Add a timestamp */ +#define XT_LOG_MASK 0x6f struct xt_log_info { unsigned char level; @@ -16,4 +17,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_ring.h b/include/net/netfilter/xt_log_ring.h new file mode 100644 index 0000000..c531381 --- /dev/null +++ b/include/net/netfilter/xt_log_ring.h @@ -0,0 +1,24 @@ +#ifndef XT_LOG_RING_H +#define XT_LOG_RING_H + +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); + +#ifdef CONFIG_NETFILTER_XT_TARGET_LOG_RING +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 +#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..62738be 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -16,6 +16,21 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -28,6 +43,45 @@ #include #include #include +#include + +#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, @@ -155,7 +209,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 +448,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 +488,20 @@ 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); + + if (loginfo->u.log.logflags & XT_LOG_ADD_TIMESTAMP) { + static struct timespec tv; + unsigned int msec; + + getnstimeofday(&tv); + msec = tv.tv_nsec; + do_div(msec, 1000000); + sb_add(m, "TIMESTAMP=%li.%03li ", tv.tv_sec, msec); + } + + sb_add(m, "%sIN=%s OUT=%s ", prefix, in ? in->name : "", out ? out->name : ""); #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge) { @@ -454,8 +519,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 +539,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 +570,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 +811,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 +859,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 +879,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 +901,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 +946,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 +1490,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 +1512,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 +1521,7 @@ module_exit(log_tg_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_AUTHOR("Jan Rekorajski "); +MODULE_AUTHOR("Richard Weinberger "); MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging"); MODULE_ALIAS("ipt_LOG"); MODULE_ALIAS("ip6t_LOG");