Skip to content

Commit

Permalink
[NETFILTER]: Extend netfilter logging API
Browse files Browse the repository at this point in the history
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: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Harald Welte authored and David S. Miller committed Aug 29, 2005
1 parent 838ab63 commit 608c8e4
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 125 deletions.
48 changes: 45 additions & 3 deletions include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,22 +114,59 @@ 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,
/* 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 net_device *in,
const struct net_device *out,
const struct nf_loginfo *li,
const char *prefix);

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

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

/* 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,
struct nf_loginfo *li,
const char *fmt, ...);

/* Activate hook; either okfn or kfree_skb called, unless a hook
Expand Down Expand Up @@ -221,6 +258,11 @@ struct nf_queue_rerouter {
extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
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 */
#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) {}
Expand Down
1 change: 1 addition & 0 deletions include/linux/netfilter_ipv4/ipt_LOG.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _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_TCPOPT 0x02 /* Log TCP options */
#define IPT_LOG_IPOPT 0x04 /* Log IP options */
Expand Down
1 change: 1 addition & 0 deletions include/linux/netfilter_ipv6/ip6t_LOG.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _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_TCPOPT 0x02 /* Log TCP options */
#define IP6T_LOG_IPOPT 0x04 /* Log IP options */
Expand Down
127 changes: 110 additions & 17 deletions net/core/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <net/sock.h>

/* In this code, we can be waiting indefinitely for userspace to
Expand Down Expand Up @@ -535,66 +536,145 @@ EXPORT_SYMBOL(skb_make_writable);

#define NF_LOG_PREFIXLEN 128

static nf_logfn *nf_logging[NPROTO]; /* = NULL */
static int reported = 0;
static struct nf_logger *nf_logging[NPROTO]; /* = NULL */
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;

/* 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], logfn);
rcu_assign_pointer(nf_logging[pf], logger);
ret = 0;
}
spin_unlock(&nf_log_lock);
return ret;
}

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

/* Give time to concurrent readers. */
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,
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];
nf_logfn *logfn;
struct nf_logger *logger;

rcu_read_lock();
logfn = rcu_dereference(nf_logging[pf]);
if (logfn) {
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] */
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++;
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_register);
EXPORT_SYMBOL(nf_log_unregister);
EXPORT_SYMBOL(nf_log_unregister_pf);
EXPORT_SYMBOL(nf_log_unregister_logger);
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
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. */
Expand All @@ -613,6 +693,9 @@ void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
void __init netfilter_init(void)
{
int i, h;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde;
#endif

queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
GFP_KERNEL);
Expand All @@ -624,6 +707,16 @@ void __init netfilter_init(void)
for (h = 0; h < NF_MAX_HOOKS; 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);
Expand Down
8 changes: 4 additions & 4 deletions net/ipv4/netfilter/ip_conntrack_proto_icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
if (icmph == NULL) {
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 ");
return -NF_ACCEPT;
}
Expand All @@ -231,13 +231,13 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
if (!(u16)csum_fold(skb->csum))
break;
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 ");
return -NF_ACCEPT;
case CHECKSUM_NONE:
if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
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 ");
return -NF_ACCEPT;
}
Expand All @@ -254,7 +254,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
*/
if (icmph->type > NR_ICMP_TYPES) {
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 ");
return -NF_ACCEPT;
}
Expand Down
Loading

0 comments on commit 608c8e4

Please sign in to comment.