Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 608c8e4f authored by Harald Welte's avatar Harald Welte Committed by David S. Miller
Browse files

[NETFILTER]: Extend netfilter logging API



This patch is in preparation to nfnetlink_log:
- loggers now have to register struct nf_logger instead of nf_logfn
- nf_log_unregister() replaced by nf_log_unregister_pf() and
  nf_log_unregister_logger()
- add comment to ip[6]t_LOG.h to assure nobody redefines flags
- add /proc/net/netfilter/nf_log to tell user which logger is currently
  registered for which address family
- if user has configured logging, but no logging backend (logger) is
  available, always spit a message to syslog, not just the first time.
- split ip[6]t_LOG.c into two parts:
  Backend: Always try to register as logger for the respective address family
  Frontend: Always log via nf_log_packet() API
- modify all users of nf_log_packet() to accomodate additional argument

Signed-off-by: default avatarHarald Welte <laforge@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 838ab636
Loading
Loading
Loading
Loading
+45 −3
Original line number Original line Diff line number Diff line
@@ -114,15 +114,51 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);


extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];


typedef void nf_logfn(unsigned int hooknum,
/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
 * disappear once iptables is replaced with pkttables.  Please DO NOT use them
 * for any new code! */
#define NF_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
#define NF_LOG_TCPOPT		0x02	/* Log TCP options */
#define NF_LOG_IPOPT		0x04	/* Log IP options */
#define NF_LOG_UID		0x08	/* Log UID owning local socket */
#define NF_LOG_MASK		0x0f

#define NF_LOG_TYPE_LOG		0x01
#define NF_LOG_TYPE_ULOG	0x02

struct nf_loginfo {
	u_int8_t type;
	union {
		struct {
			u_int32_t copy_len;
			u_int16_t group;
			u_int16_t qthreshold;
		} ulog;
		struct {
			u_int8_t level;
			u_int8_t logflags;
		} log;
	} u;
};

typedef void nf_logfn(unsigned int pf,
		      unsigned int hooknum,
		      const struct sk_buff *skb,
		      const struct sk_buff *skb,
		      const struct net_device *in,
		      const struct net_device *in,
		      const struct net_device *out,
		      const struct net_device *out,
		      const struct nf_loginfo *li,
		      const char *prefix);
		      const char *prefix);


struct nf_logger {
	struct module	*me;
	nf_logfn 	*logfn;
	char		*name;
};

/* Function to register/unregister log function. */
/* Function to register/unregister log function. */
int nf_log_register(int pf, nf_logfn *logfn);
int nf_log_register(int pf, struct nf_logger *logger);
void nf_log_unregister(int pf, nf_logfn *logfn);
void nf_log_unregister_pf(int pf);
void nf_log_unregister_logger(struct nf_logger *logger);


/* Calls the registered backend logging function */
/* Calls the registered backend logging function */
void nf_log_packet(int pf,
void nf_log_packet(int pf,
@@ -130,6 +166,7 @@ void nf_log_packet(int pf,
		   const struct sk_buff *skb,
		   const struct sk_buff *skb,
		   const struct net_device *in,
		   const struct net_device *in,
		   const struct net_device *out,
		   const struct net_device *out,
		   struct nf_loginfo *li,
		   const char *fmt, ...);
		   const char *fmt, ...);
                   
                   
/* Activate hook; either okfn or kfree_skb called, unless a hook
/* Activate hook; either okfn or kfree_skb called, unless a hook
@@ -221,6 +258,11 @@ struct nf_queue_rerouter {
extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
extern int nf_unregister_queue_rerouter(int pf);
extern int nf_unregister_queue_rerouter(int pf);


#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
extern struct proc_dir_entry *proc_net_netfilter;
#endif

#else /* !CONFIG_NETFILTER */
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
+1 −0
Original line number Original line Diff line number Diff line
#ifndef _IPT_LOG_H
#ifndef _IPT_LOG_H
#define _IPT_LOG_H
#define _IPT_LOG_H


/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
#define IPT_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
#define IPT_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
#define IPT_LOG_TCPOPT		0x02	/* Log TCP options */
#define IPT_LOG_TCPOPT		0x02	/* Log TCP options */
#define IPT_LOG_IPOPT		0x04	/* Log IP options */
#define IPT_LOG_IPOPT		0x04	/* Log IP options */
+1 −0
Original line number Original line Diff line number Diff line
#ifndef _IP6T_LOG_H
#ifndef _IP6T_LOG_H
#define _IP6T_LOG_H
#define _IP6T_LOG_H


/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
#define IP6T_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
#define IP6T_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
#define IP6T_LOG_TCPOPT		0x02	/* Log TCP options */
#define IP6T_LOG_TCPOPT		0x02	/* Log TCP options */
#define IP6T_LOG_IPOPT		0x04	/* Log IP options */
#define IP6T_LOG_IPOPT		0x04	/* Log IP options */
+110 −17
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/if.h>
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <net/sock.h>
#include <net/sock.h>


/* In this code, we can be waiting indefinitely for userspace to
/* In this code, we can be waiting indefinitely for userspace to
@@ -535,11 +536,10 @@ EXPORT_SYMBOL(skb_make_writable);


#define NF_LOG_PREFIXLEN		128
#define NF_LOG_PREFIXLEN		128


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


int nf_log_register(int pf, nf_logfn *logfn)
int nf_log_register(int pf, struct nf_logger *logger)
{
{
	int ret = -EBUSY;
	int ret = -EBUSY;


@@ -547,17 +547,16 @@ int nf_log_register(int pf, nf_logfn *logfn)
	 * substituting pointer. */
	 * substituting pointer. */
	spin_lock(&nf_log_lock);
	spin_lock(&nf_log_lock);
	if (!nf_logging[pf]) {
	if (!nf_logging[pf]) {
		rcu_assign_pointer(nf_logging[pf], logfn);
		rcu_assign_pointer(nf_logging[pf], logger);
		ret = 0;
		ret = 0;
	}
	}
	spin_unlock(&nf_log_lock);
	spin_unlock(&nf_log_lock);
	return ret;
	return ret;
}		
}		


void nf_log_unregister(int pf, nf_logfn *logfn)
void nf_log_unregister_pf(int pf)
{
{
	spin_lock(&nf_log_lock);
	spin_lock(&nf_log_lock);
	if (nf_logging[pf] == logfn)
	nf_logging[pf] = NULL;
	nf_logging[pf] = NULL;
	spin_unlock(&nf_log_lock);
	spin_unlock(&nf_log_lock);


@@ -565,36 +564,117 @@ void nf_log_unregister(int pf, nf_logfn *logfn)
	synchronize_net();
	synchronize_net();
}
}


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();
}

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


#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_net_netfilter;
EXPORT_SYMBOL(proc_net_netfilter);

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 */


/* This does not belong here, but locally generated errors need it if connection
/* This does not belong here, but locally generated errors need it if connection
   tracking in use: without this, connection may not be in hash table, and hence
   tracking in use: without this, connection may not be in hash table, and hence
   manufactured ICMP or RST packets will not be associated with it. */
   manufactured ICMP or RST packets will not be associated with it. */
@@ -613,6 +693,9 @@ void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
void __init netfilter_init(void)
void __init netfilter_init(void)
{
{
	int i, h;
	int i, h;
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry *pde;
#endif


	queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
	queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
				 GFP_KERNEL);
				 GFP_KERNEL);
@@ -624,6 +707,16 @@ void __init netfilter_init(void)
		for (h = 0; h < NF_MAX_HOOKS; h++)
		for (h = 0; h < NF_MAX_HOOKS; h++)
			INIT_LIST_HEAD(&nf_hooks[i][h]);
			INIT_LIST_HEAD(&nf_hooks[i][h]);
	}
	}

#ifdef CONFIG_PROC_FS
	proc_net_netfilter = proc_mkdir("netfilter", proc_net);
	if (!proc_net_netfilter)
		panic("cannot create netfilter proc entry");
	pde = create_proc_entry("nf_log", S_IRUGO, proc_net_netfilter);
	if (!pde)
		panic("cannot create /proc/net/netfilter/nf_log");
	pde->proc_fops = &nflog_file_ops;
#endif
}
}


EXPORT_SYMBOL(ip_ct_attach);
EXPORT_SYMBOL(ip_ct_attach);
+4 −4
Original line number Original line Diff line number Diff line
@@ -217,7 +217,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
	icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
	icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
	if (icmph == NULL) {
	if (icmph == NULL) {
		if (LOG_INVALID(IPPROTO_ICMP))
		if (LOG_INVALID(IPPROTO_ICMP))
			nf_log_packet(PF_INET, 0, skb, NULL, NULL,
			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
				      "ip_ct_icmp: short packet ");
				      "ip_ct_icmp: short packet ");
		return -NF_ACCEPT;
		return -NF_ACCEPT;
	}
	}
@@ -231,13 +231,13 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
		if (!(u16)csum_fold(skb->csum)) 
		if (!(u16)csum_fold(skb->csum)) 
			break;
			break;
		if (LOG_INVALID(IPPROTO_ICMP))
		if (LOG_INVALID(IPPROTO_ICMP))
			nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
				      "ip_ct_icmp: bad HW ICMP checksum ");
				      "ip_ct_icmp: bad HW ICMP checksum ");
		return -NF_ACCEPT;
		return -NF_ACCEPT;
	case CHECKSUM_NONE:
	case CHECKSUM_NONE:
		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
			if (LOG_INVALID(IPPROTO_ICMP))
			if (LOG_INVALID(IPPROTO_ICMP))
				nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
				nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
					      "ip_ct_icmp: bad ICMP checksum ");
					      "ip_ct_icmp: bad ICMP checksum ");
			return -NF_ACCEPT;
			return -NF_ACCEPT;
		}
		}
@@ -254,7 +254,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
	 */
	 */
	if (icmph->type > NR_ICMP_TYPES) {
	if (icmph->type > NR_ICMP_TYPES) {
		if (LOG_INVALID(IPPROTO_ICMP))
		if (LOG_INVALID(IPPROTO_ICMP))
			nf_log_packet(PF_INET, 0, skb, NULL, NULL,
			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
				      "ip_ct_icmp: invalid ICMP type ");
				      "ip_ct_icmp: invalid ICMP type ");
		return -NF_ACCEPT;
		return -NF_ACCEPT;
	}
	}
Loading