Commit 62c12ea9 authored by Harald Welte's avatar Harald Welte Committed by Linus Torvalds

[NETFILTER]: Add nf_log handler, from Jozsef Kadlecsik.

parent f7e36893
......@@ -99,6 +99,24 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
typedef void nf_logfn(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *prefix);
/* Function to register/unregister log function. */
int nf_log_register(int pf, nf_logfn *logfn);
void nf_log_unregister(int pf, nf_logfn *logfn);
/* Calls the registered backend logging function */
void nf_log_packet(int pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *fmt, ...);
/* Activate hook; either okfn or kfree_skb called, unless a hook
returns NF_STOLEN (in which case, it's up to the hook to deal with
the consequences).
......
......@@ -11,6 +11,9 @@
#define NETLINK_NFLOG 5
#endif
#define ULOG_DEFAULT_NLGROUP 1
#define ULOG_DEFAULT_QTHRESHOLD 1
#define ULOG_MAC_LEN 80
#define ULOG_PREFIX_LEN 32
......
......@@ -8,8 +8,10 @@
*
* February 2000: Modified by James Morris to have 1 queue per protocol.
* 15-Mar-2000: Added NF_REPEAT --RR.
* 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <net/protocol.h>
#include <linux/init.h>
......@@ -741,6 +743,72 @@ int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
EXPORT_SYMBOL(skb_ip_make_writable);
#endif /*CONFIG_INET*/
/* Internal logging interface, which relies on the real
LOG target modules */
#define NF_LOG_PREFIXLEN 128
static nf_logfn *nf_logging[NPROTO]; /* = NULL */
static int reported = 0;
static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
int nf_log_register(int pf, nf_logfn *logfn)
{
int ret = -EBUSY;
/* Any setup of logging members must be done before
* substituting pointer. */
smp_wmb();
spin_lock(&nf_log_lock);
if (!nf_logging[pf]) {
nf_logging[pf] = logfn;
ret = 0;
}
spin_unlock(&nf_log_lock);
return ret;
}
void nf_log_unregister(int pf, nf_logfn *logfn)
{
spin_lock(&nf_log_lock);
if (nf_logging[pf] == logfn)
nf_logging[pf] = NULL;
spin_unlock(&nf_log_lock);
/* Give time to concurrent readers. */
synchronize_net();
}
void nf_log_packet(int pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *fmt, ...)
{
va_list args;
char prefix[NF_LOG_PREFIXLEN];
nf_logfn *logfn;
rcu_read_lock();
logfn = nf_logging[pf];
if (logfn) {
va_start(args, fmt);
vsnprintf(prefix, sizeof(prefix), fmt, args);
va_end(args);
/* We must read logging before nf_logfn[pf] */
smp_read_barrier_depends();
logfn(hooknum, skb, in, out, prefix);
} else if (!reported) {
printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
"no backend logging module loaded in!\n");
reported++;
}
rcu_read_unlock();
}
EXPORT_SYMBOL(nf_log_register);
EXPORT_SYMBOL(nf_log_unregister);
EXPORT_SYMBOL(nf_log_packet);
/* This does not belong here, but ipt_REJECT needs it if connection
tracking in use: without this, connection may not be in hash table,
......
......@@ -19,6 +19,7 @@
#include <net/tcp.h>
#include <net/route.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
......@@ -26,6 +27,10 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables syslog logging module");
static unsigned int nflog = 1;
MODULE_PARM(nflog, "i");
MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
#if 0
#define DEBUGP printk
#else
......@@ -324,28 +329,25 @@ static void dump_packet(const struct ipt_log_info *info,
/* maxlen = 230+ 91 + 230 + 252 = 803 */
}
static unsigned int
ipt_log_target(struct sk_buff **pskb,
static void
ipt_log_packet(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
const struct ipt_log_info *loginfo,
const char *level_string,
const char *prefix)
{
const struct ipt_log_info *loginfo = targinfo;
char level_string[4] = "< >";
level_string[1] = '0' + (loginfo->level % 8);
spin_lock_bh(&log_lock);
printk(level_string);
printk("%sIN=%s OUT=%s ",
loginfo->prefix,
prefix == NULL ? loginfo->prefix : prefix,
in ? in->name : "",
out ? out->name : "");
#ifdef CONFIG_BRIDGE_NETFILTER
if ((*pskb)->nf_bridge) {
struct net_device *physindev = (*pskb)->nf_bridge->physindev;
struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
if (skb->nf_bridge) {
struct net_device *physindev = skb->nf_bridge->physindev;
struct net_device *physoutdev = skb->nf_bridge->physoutdev;
if (physindev && in != physindev)
printk("PHYSIN=%s ", physindev->name);
......@@ -357,25 +359,56 @@ ipt_log_target(struct sk_buff **pskb,
if (in && !out) {
/* MAC logging for input chain only. */
printk("MAC=");
if ((*pskb)->dev && (*pskb)->dev->hard_header_len
&& (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
if (skb->dev && skb->dev->hard_header_len
&& skb->mac.raw != (void*)skb->nh.iph) {
int i;
unsigned char *p = (*pskb)->mac.raw;
for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
unsigned char *p = skb->mac.raw;
for (i = 0; i < skb->dev->hard_header_len; i++,p++)
printk("%02x%c", *p,
i==(*pskb)->dev->hard_header_len - 1
i==skb->dev->hard_header_len - 1
? ' ':':');
} else
printk(" ");
}
dump_packet(loginfo, *pskb, 0);
dump_packet(loginfo, skb, 0);
printk("\n");
spin_unlock_bh(&log_lock);
}
static unsigned int
ipt_log_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
const struct ipt_log_info *loginfo = targinfo;
char level_string[4] = "< >";
level_string[1] = '0' + (loginfo->level % 8);
ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
return IPT_CONTINUE;
}
static void
ipt_logfn(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *prefix)
{
struct ipt_log_info loginfo = {
.level = 0,
.logflags = IPT_LOG_MASK,
.prefix = ""
};
ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
}
static int ipt_log_checkentry(const char *tablename,
const struct ipt_entry *e,
void *targinfo,
......@@ -413,11 +446,18 @@ static struct ipt_target ipt_log_reg = {
static int __init init(void)
{
return ipt_register_target(&ipt_log_reg);
if (ipt_register_target(&ipt_log_reg))
return -EINVAL;
if (nflog)
nf_log_register(PF_INET, &ipt_logfn);
return 0;
}
static void __exit fini(void)
{
if (nflog)
nf_log_unregister(PF_INET, &ipt_logfn);
ipt_unregister_target(&ipt_log_reg);
}
......
......@@ -50,6 +50,7 @@
#include <linux/netlink.h>
#include <linux/netdevice.h>
#include <linux/mm.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
#include <linux/netfilter_ipv4/lockhelp.h>
......@@ -80,6 +81,10 @@ static unsigned int flushtimeout = 10 * HZ;
MODULE_PARM(flushtimeout, "i");
MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
static unsigned int nflog = 1;
MODULE_PARM(nflog, "i");
MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
/* global data structures */
typedef struct {
......@@ -157,17 +162,17 @@ struct sk_buff *ulog_alloc_skb(unsigned int size)
return skb;
}
static unsigned int ipt_ulog_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo, void *userinfo)
static void ipt_ulog_packet(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const struct ipt_ulog_info *loginfo,
const char *prefix)
{
ulog_buff_t *ub;
ulog_packet_msg_t *pm;
size_t size, copy_len;
struct nlmsghdr *nlh;
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
/* ffs == find first bit set, necessary because userspace
* is already shifting groupnumber, but we need unshifted.
......@@ -176,8 +181,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
/* calculate the size of the skb needed */
if ((loginfo->copy_range == 0) ||
(loginfo->copy_range > (*pskb)->len)) {
copy_len = (*pskb)->len;
(loginfo->copy_range > skb->len)) {
copy_len = skb->len;
} else {
copy_len = loginfo->copy_range;
}
......@@ -214,19 +219,21 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
/* copy hook, prefix, timestamp, payload, etc. */
pm->data_len = copy_len;
pm->timestamp_sec = (*pskb)->stamp.tv_sec;
pm->timestamp_usec = (*pskb)->stamp.tv_usec;
pm->mark = (*pskb)->nfmark;
pm->timestamp_sec = skb->stamp.tv_sec;
pm->timestamp_usec = skb->stamp.tv_usec;
pm->mark = skb->nfmark;
pm->hook = hooknum;
if (loginfo->prefix[0] != '\0')
if (prefix != NULL)
strncpy(pm->prefix, prefix, sizeof(pm->prefix));
else if (loginfo->prefix[0] != '\0')
strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
else
*(pm->prefix) = '\0';
if (in && in->hard_header_len > 0
&& (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
&& skb->mac.raw != (void *) skb->nh.iph
&& in->hard_header_len <= ULOG_MAC_LEN) {
memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
pm->mac_len = in->hard_header_len;
} else
pm->mac_len = 0;
......@@ -241,8 +248,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
else
pm->outdev_name[0] = '\0';
/* copy_len <= (*pskb)->len, so can't fail. */
if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
/* copy_len <= skb->len, so can't fail. */
if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
BUG();
/* check if we are building multi-part messages */
......@@ -266,8 +273,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
UNLOCK_BH(&ulog_lock);
return IPT_CONTINUE;
return;
nlmsg_failure:
PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
......@@ -276,8 +282,35 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
PRINTR("ipt_ULOG: Error building netlink message\n");
UNLOCK_BH(&ulog_lock);
}
return IPT_CONTINUE;
static unsigned int ipt_ulog_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo, void *userinfo)
{
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
return IPT_CONTINUE;
}
static void ipt_logfn(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *prefix)
{
struct ipt_ulog_info loginfo = {
.nl_group = ULOG_DEFAULT_NLGROUP,
.copy_range = 0,
.qthreshold = ULOG_DEFAULT_QTHRESHOLD,
.prefix = ""
};
ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
}
static int ipt_ulog_checkentry(const char *tablename,
......@@ -341,7 +374,9 @@ static int __init init(void)
sock_release(nflognl->sk_socket);
return -EINVAL;
}
if (nflog)
nf_log_register(PF_INET, &ipt_logfn);
return 0;
}
......@@ -352,6 +387,8 @@ static void __exit fini(void)
DEBUGP("ipt_ULOG: cleanup_module\n");
if (nflog)
nf_log_unregister(PF_INET, &ipt_logfn);
ipt_unregister_target(&ipt_ulog_reg);
sock_release(nflognl->sk_socket);
......
......@@ -18,12 +18,17 @@
#include <net/udp.h>
#include <net/tcp.h>
#include <net/ipv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
MODULE_DESCRIPTION("IP6 tables LOG target module");
MODULE_LICENSE("GPL");
static unsigned int nflog = 1;
MODULE_PARM(nflog, "i");
MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
struct in_device;
#include <net/route.h>
#include <linux/netfilter_ipv6/ip6t_LOG.h>
......@@ -265,40 +270,38 @@ static void dump_packet(const struct ip6t_log_info *info,
}
}
static unsigned int
ip6t_log_target(struct sk_buff **pskb,
unsigned int hooknum,
static void
ip6t_log_packet(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
void *userinfo)
const struct ip6t_log_info *loginfo,
const char *level_string,
const char *prefix)
{
struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
const struct ip6t_log_info *loginfo = targinfo;
char level_string[4] = "< >";
struct ipv6hdr *ipv6h = skb->nh.ipv6h;
level_string[1] = '0' + (loginfo->level % 8);
spin_lock_bh(&log_lock);
printk(level_string);
printk("%sIN=%s OUT=%s ",
loginfo->prefix,
prefix == NULL ? loginfo->prefix : prefix,
in ? in->name : "",
out ? out->name : "");
if (in && !out) {
/* MAC logging for input chain only. */
printk("MAC=");
if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
if ((*pskb)->dev->type != ARPHRD_SIT){
if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
if (skb->dev->type != ARPHRD_SIT){
int i;
unsigned char *p = (*pskb)->mac.raw;
for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
unsigned char *p = skb->mac.raw;
for (i = 0; i < skb->dev->hard_header_len; i++,p++)
printk("%02x%c", *p,
i==(*pskb)->dev->hard_header_len - 1
i==skb->dev->hard_header_len - 1
? ' ':':');
} else {
int i;
unsigned char *p = (*pskb)->mac.raw;
if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
unsigned char *p = skb->mac.raw;
if ( p - (ETH_ALEN*2+2) > skb->head ){
p -= (ETH_ALEN+2);
for (i = 0; i < (ETH_ALEN); i++,p++)
printk("%02x%s", *p,
......@@ -309,10 +312,10 @@ ip6t_log_target(struct sk_buff **pskb,
i == ETH_ALEN-1 ? ' ' : ':');
}
if (((*pskb)->dev->addr_len == 4) &&
(*pskb)->dev->hard_header_len > 20){
if ((skb->dev->addr_len == 4) &&
skb->dev->hard_header_len > 20){
printk("TUNNEL=");
p = (*pskb)->mac.raw + 12;
p = skb->mac.raw + 12;
for (i = 0; i < 4; i++,p++)
printk("%3d%s", *p,
i == 3 ? "->" : ".");
......@@ -328,10 +331,41 @@ ip6t_log_target(struct sk_buff **pskb,
dump_packet(loginfo, ipv6h, 1);
printk("\n");
spin_unlock_bh(&log_lock);
}
static unsigned int
ip6t_log_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
void *userinfo)
{
const struct ip6t_log_info *loginfo = targinfo;
char level_string[4] = "< >";
level_string[1] = '0' + (loginfo->level % 8);
ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
return IP6T_CONTINUE;
}
static void
ip6t_logfn(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const char *prefix)
{
struct ip6t_log_info loginfo = {
.level = 0,
.logflags = IP6T_LOG_MASK,
.prefix = ""
};
ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
}
static int ip6t_log_checkentry(const char *tablename,
const struct ip6t_entry *e,
void *targinfo,
......@@ -360,20 +394,27 @@ static int ip6t_log_checkentry(const char *tablename,
return 1;
}
static struct ip6t_target ip6t_log_reg
= { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL,
THIS_MODULE };
static struct ip6t_target ip6t_log_reg = {
.name = "LOG",
.target = ip6t_log_target,
.checkentry = ip6t_log_checkentry,
.me = THIS_MODULE,
};
static int __init init(void)
{
if (ip6t_register_target(&ip6t_log_reg))
return -EINVAL;
if (nflog)
nf_log_register(PF_INET6, &ip6t_logfn);
return 0;
}
static void __exit fini(void)
{
if (nflog)
nf_log_unregister(PF_INET6, &ip6t_logfn);
ip6t_unregister_target(&ip6t_log_reg);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment