Commit eccf6f14 authored by David S. Miller's avatar David S. Miller

Merge

parents 0180f946 516e49e0
...@@ -99,6 +99,24 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg); ...@@ -99,6 +99,24 @@ 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,
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 /* 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 returns NF_STOLEN (in which case, it's up to the hook to deal with
the consequences). the consequences).
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
enum nf_ip_hook_priorities { enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN, NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK_DEFRAG = -400,
NF_IP_PRI_RAW = -300,
NF_IP_PRI_SELINUX_FIRST = -225, NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200, NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175, NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
......
...@@ -252,6 +252,9 @@ extern void ip_ct_refresh(struct ip_conntrack *ct, ...@@ -252,6 +252,9 @@ extern void ip_ct_refresh(struct ip_conntrack *ct,
/* Call me when a conntrack is destroyed. */ /* Call me when a conntrack is destroyed. */
extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
/* Fake conntrack entry for untracked connections */
extern struct ip_conntrack ip_conntrack_untracked;
/* Returns new sk_buff, or NULL */ /* Returns new sk_buff, or NULL */
struct sk_buff * struct sk_buff *
ip_ct_gather_frags(struct sk_buff *skb); ip_ct_gather_frags(struct sk_buff *skb);
......
...@@ -35,9 +35,13 @@ extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *); ...@@ -35,9 +35,13 @@ extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
/* Allocate space for an expectation: this is mandatory before calling
ip_conntrack_expect_related. */
extern struct ip_conntrack_expect *ip_conntrack_expect_alloc(void);
/* Add an expected connection: can have more than one per connection */ /* Add an expected connection: can have more than one per connection */
extern int ip_conntrack_expect_related(struct ip_conntrack *related_to, extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp,
struct ip_conntrack_expect *exp); struct ip_conntrack *related_to);
extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
struct ip_conntrack_tuple *newtuple); struct ip_conntrack_tuple *newtuple);
extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp); extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
......
/* IPv4 macros for the internal logging interface. */
#ifndef __IP_LOGGING_H
#define __IP_LOGGING_H
#ifdef __KERNEL__
#include <linux/socket.h>
#include <linux/netfilter_logging.h>
#define nf_log_ip_packet(pskb,hooknum,in,out,fmt,args...) \
nf_log_packet(AF_INET,pskb,hooknum,in,out,fmt,##args)
#define nf_log_ip(pfh,len,fmt,args...) \
nf_log(AF_INET,pfh,len,fmt,##args)
#define nf_ip_log_register(logging) nf_log_register(AF_INET,logging)
#define nf_ip_log_unregister(logging) nf_log_unregister(AF_INET,logging)
#endif /*__KERNEL__*/
#endif /*__IP_LOGGING_H*/
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#define NETLINK_NFLOG 5 #define NETLINK_NFLOG 5
#endif #endif
#define ULOG_DEFAULT_NLGROUP 1
#define ULOG_DEFAULT_QTHRESHOLD 1
#define ULOG_MAC_LEN 80 #define ULOG_MAC_LEN 80
#define ULOG_PREFIX_LEN 32 #define ULOG_PREFIX_LEN 32
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1)) #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2)) #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
/* flags, invflags: */ /* flags, invflags: */
#define IPT_CONNTRACK_STATE 0x01 #define IPT_CONNTRACK_STATE 0x01
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
#define IPT_STATE_INVALID (1 << 0) #define IPT_STATE_INVALID (1 << 0)
#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
struct ipt_state_info struct ipt_state_info
{ {
unsigned int statemask; unsigned int statemask;
......
/* IPv6 macros for the nternal logging interface. */
#ifndef __IP6_LOGGING_H
#define __IP6_LOGGING_H
#ifdef __KERNEL__
#include <linux/socket.h>
#include <linux/netfilter_logging.h>
#define nf_log_ip6_packet(pskb,hooknum,in,out,fmt,args...) \
nf_log_packet(AF_INET6,pskb,hooknum,in,out,fmt,##args)
#define nf_log_ip6(pfh,len,fmt,args...) \
nf_log(AF_INET6,pfh,len,fmt,##args)
#define nf_ip6_log_register(logging) nf_log_register(AF_INET6,logging)
#define nf_ip6_log_unregister(logging) nf_log_unregister(AF_INET6,logging)
#endif /*__KERNEL__*/
#endif /*__IP6_LOGGING_H*/
/* Internal logging interface, which relies on the real
LOG target modules */
#ifndef __LINUX_NETFILTER_LOGGING_H
#define __LINUX_NETFILTER_LOGGING_H
#ifdef __KERNEL__
#include <asm/atomic.h>
struct nf_logging_t {
void (*nf_log_packet)(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const char *prefix);
void (*nf_log)(char *pfh, size_t len,
const char *prefix);
};
extern void nf_log_register(int pf, const struct nf_logging_t *logging);
extern void nf_log_unregister(int pf, const struct nf_logging_t *logging);
extern void nf_log_packet(int pf,
struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const char *fmt, ...);
extern void nf_log(int pf,
char *pfh, size_t len,
const char *fmt, ...);
#endif /*__KERNEL__*/
#endif /*__LINUX_NETFILTER_LOGGING_H*/
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
* *
* February 2000: Modified by James Morris to have 1 queue per protocol. * February 2000: Modified by James Morris to have 1 queue per protocol.
* 15-Mar-2000: Added NF_REPEAT --RR. * 15-Mar-2000: Added NF_REPEAT --RR.
* 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -741,6 +743,72 @@ int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) ...@@ -741,6 +743,72 @@ int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
EXPORT_SYMBOL(skb_ip_make_writable); EXPORT_SYMBOL(skb_ip_make_writable);
#endif /*CONFIG_INET*/ #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 /* This does not belong here, but ipt_REJECT needs it if connection
tracking in use: without this, connection may not be in hash table, tracking in use: without this, connection may not be in hash table,
......
...@@ -579,5 +579,29 @@ config IP_NF_COMPAT_IPFWADM ...@@ -579,5 +579,29 @@ config IP_NF_COMPAT_IPFWADM
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_NOTRACK
tristate 'NOTRACK target support'
depends on IP_NF_RAW
help
The NOTRACK target allows a select rule to specify
which packets *not* to enter the conntrack/NAT
subsystem with all the consequences (no ICMP error tracking,
no protocol helpers for the selected packets).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP_NF_RAW
tristate 'raw table support (required for NOTRACK/TRACE)'
depends on IP_NF_IPTABLES
help
This option adds a `raw' table to iptables. This table is the very
first in the netfilter framework and hooks in at the PREROUTING
and OUTPUT chains.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
help
endmenu endmenu
...@@ -38,6 +38,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o ...@@ -38,6 +38,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches # matches
obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
...@@ -81,6 +82,7 @@ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o ...@@ -81,6 +82,7 @@ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
# generic ARP tables # generic ARP tables
obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
......
...@@ -46,10 +46,11 @@ static DECLARE_LOCK(amanda_buffer_lock); ...@@ -46,10 +46,11 @@ static DECLARE_LOCK(amanda_buffer_lock);
static int help(struct sk_buff *skb, static int help(struct sk_buff *skb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{ {
struct ip_conntrack_expect exp; struct ip_conntrack_expect *exp;
struct ip_ct_amanda_expect *exp_amanda_info; struct ip_ct_amanda_expect *exp_amanda_info;
char *data, *data_limit, *tmp; char *data, *data_limit, *tmp;
unsigned int dataoff, i; unsigned int dataoff, i;
u_int16_t port, len;
/* Only look at packets from the Amanda server */ /* Only look at packets from the Amanda server */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
...@@ -79,33 +80,40 @@ static int help(struct sk_buff *skb, ...@@ -79,33 +80,40 @@ static int help(struct sk_buff *skb,
goto out; goto out;
data += strlen("CONNECT "); data += strlen("CONNECT ");
memset(&exp, 0, sizeof(exp));
exp.tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp.tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
exp.tuple.dst.protonum = IPPROTO_TCP;
exp.mask.src.ip = 0xFFFFFFFF;
exp.mask.dst.ip = 0xFFFFFFFF;
exp.mask.dst.protonum = 0xFFFF;
exp.mask.dst.u.tcp.port = 0xFFFF;
/* Only search first line. */ /* Only search first line. */
if ((tmp = strchr(data, '\n'))) if ((tmp = strchr(data, '\n')))
*tmp = '\0'; *tmp = '\0';
exp_amanda_info = &exp.help.exp_amanda_info;
for (i = 0; i < ARRAY_SIZE(conns); i++) { for (i = 0; i < ARRAY_SIZE(conns); i++) {
char *match = strstr(data, conns[i]); char *match = strstr(data, conns[i]);
if (!match) if (!match)
continue; continue;
tmp = data = match + strlen(conns[i]); tmp = data = match + strlen(conns[i]);
exp_amanda_info->offset = data - amanda_buffer; port = simple_strtoul(data, &data, 10);
exp_amanda_info->port = simple_strtoul(data, &data, 10); len = data - tmp;
exp_amanda_info->len = data - tmp; if (port == 0 || len > 5)
if (exp_amanda_info->port == 0 || exp_amanda_info->len > 5)
break; break;
exp.tuple.dst.u.tcp.port = htons(exp_amanda_info->port); exp = ip_conntrack_expect_alloc();
ip_conntrack_expect_related(ct, &exp); if (exp == NULL)
goto out;
exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
exp->tuple.dst.protonum = IPPROTO_TCP;
exp->mask.src.ip = 0xFFFFFFFF;
exp->mask.dst.ip = 0xFFFFFFFF;
exp->mask.dst.protonum = 0xFFFF;
exp->mask.dst.u.tcp.port = 0xFFFF;
exp_amanda_info = &exp->help.exp_amanda_info;
exp_amanda_info->offset = data - amanda_buffer;
exp_amanda_info->port = port;
exp_amanda_info->len = len;
exp->tuple.dst.u.tcp.port = htons(port);
ip_conntrack_expect_related(exp, ct);
} }
out: out:
......
...@@ -67,6 +67,7 @@ int ip_conntrack_max; ...@@ -67,6 +67,7 @@ int ip_conntrack_max;
static atomic_t ip_conntrack_count = ATOMIC_INIT(0); static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
struct list_head *ip_conntrack_hash; struct list_head *ip_conntrack_hash;
static kmem_cache_t *ip_conntrack_cachep; static kmem_cache_t *ip_conntrack_cachep;
struct ip_conntrack ip_conntrack_untracked;
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
...@@ -794,6 +795,15 @@ unsigned int ip_conntrack_in(unsigned int hooknum, ...@@ -794,6 +795,15 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
int set_reply; int set_reply;
int ret; int ret;
/* Never happen */
if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
(*pskb)->nh.iph->protocol, hooknum);
}
return NF_DROP;
}
/* FIXME: Do this right please. --RR */ /* FIXME: Do this right please. --RR */
(*pskb)->nfcache |= NFC_UNKNOWN; (*pskb)->nfcache |= NFC_UNKNOWN;
...@@ -812,18 +822,10 @@ unsigned int ip_conntrack_in(unsigned int hooknum, ...@@ -812,18 +822,10 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
} }
#endif #endif
/* Previously seen (loopback)? Ignore. Do this before /* Previously seen (loopback or untracked)? Ignore. */
fragment check. */
if ((*pskb)->nfct) if ((*pskb)->nfct)
return NF_ACCEPT; return NF_ACCEPT;
/* Gather fragments. */
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb);
if (!*pskb)
return NF_STOLEN;
}
proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
/* It may be an icmp error... */ /* It may be an icmp error... */
...@@ -917,11 +919,55 @@ static void expectation_timed_out(unsigned long ul_expect) ...@@ -917,11 +919,55 @@ static void expectation_timed_out(unsigned long ul_expect)
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
} }
struct ip_conntrack_expect *
ip_conntrack_expect_alloc()
{
struct ip_conntrack_expect *new;
new = (struct ip_conntrack_expect *)
kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
if (!new) {
DEBUGP("expect_related: OOM allocating expect\n");
return NULL;
}
/* tuple_cmp compares whole union, we have to initialized cleanly */
memset(new, 0, sizeof(struct ip_conntrack_expect));
return new;
}
static void
ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
struct ip_conntrack *related_to)
{
DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
new->expectant = related_to;
new->sibling = NULL;
atomic_set(&new->use, 1);
/* add to expected list for this connection */
list_add(&new->expected_list, &related_to->sibling_list);
/* add to global list of expectations */
list_prepend(&ip_conntrack_expect_list, &new->list);
/* add and start timer if required */
if (related_to->helper->timeout) {
init_timer(&new->timeout);
new->timeout.data = (unsigned long)new;
new->timeout.function = expectation_timed_out;
new->timeout.expires = jiffies +
related_to->helper->timeout * HZ;
add_timer(&new->timeout);
}
related_to->expecting++;
}
/* Add a related connection. */ /* Add a related connection. */
int ip_conntrack_expect_related(struct ip_conntrack *related_to, int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
struct ip_conntrack_expect *expect) struct ip_conntrack *related_to)
{ {
struct ip_conntrack_expect *old, *new; struct ip_conntrack_expect *old;
int ret = 0; int ret = 0;
WRITE_LOCK(&ip_conntrack_lock); WRITE_LOCK(&ip_conntrack_lock);
...@@ -943,7 +989,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -943,7 +989,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
if (related_to->helper->timeout) { if (related_to->helper->timeout) {
if (!del_timer(&old->timeout)) { if (!del_timer(&old->timeout)) {
/* expectation is dying. Fall through */ /* expectation is dying. Fall through */
old = NULL; goto out;
} else { } else {
old->timeout.expires = jiffies + old->timeout.expires = jiffies +
related_to->helper->timeout * HZ; related_to->helper->timeout * HZ;
...@@ -951,10 +997,10 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -951,10 +997,10 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
} }
} }
if (old) {
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
kfree(expect);
return -EEXIST; return -EEXIST;
}
} else if (related_to->helper->max_expected && } else if (related_to->helper->max_expected &&
related_to->expecting >= related_to->helper->max_expected) { related_to->expecting >= related_to->helper->max_expected) {
struct list_head *cur_item; struct list_head *cur_item;
...@@ -971,6 +1017,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -971,6 +1017,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
related_to->helper->name, related_to->helper->name,
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
kfree(expect);
return -EPERM; return -EPERM;
} }
DEBUGP("ip_conntrack: max number of expected " DEBUGP("ip_conntrack: max number of expected "
...@@ -1010,37 +1057,12 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -1010,37 +1057,12 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
&expect->mask)) { &expect->mask)) {
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_related: busy!\n"); DEBUGP("expect_related: busy!\n");
return -EBUSY;
}
new = (struct ip_conntrack_expect *) kfree(expect);
kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC); return -EBUSY;
if (!new) {
WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_relaed: OOM allocating expect\n");
return -ENOMEM;
} }
DEBUGP("new expectation %p of conntrack %p\n", new, related_to); out: ip_conntrack_expect_insert(expect, related_to);
memcpy(new, expect, sizeof(*expect));
new->expectant = related_to;
new->sibling = NULL;
atomic_set(&new->use, 1);
/* add to expected list for this connection */
list_add(&new->expected_list, &related_to->sibling_list);
/* add to global list of expectations */
list_prepend(&ip_conntrack_expect_list, &new->list);
/* add and start timer if required */
if (related_to->helper->timeout) {
init_timer(&new->timeout);
new->timeout.data = (unsigned long)new;
new->timeout.function = expectation_timed_out;
new->timeout.expires = jiffies +
related_to->helper->timeout * HZ;
add_timer(&new->timeout);
}
related_to->expecting++;
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
...@@ -1158,18 +1180,18 @@ void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) ...@@ -1158,18 +1180,18 @@ void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
{ {
IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
WRITE_LOCK(&ip_conntrack_lock);
/* If not in hash table, timer will not be active yet */ /* If not in hash table, timer will not be active yet */
if (!is_confirmed(ct)) if (!is_confirmed(ct))
ct->timeout.expires = extra_jiffies; ct->timeout.expires = extra_jiffies;
else { else {
WRITE_LOCK(&ip_conntrack_lock);
/* Need del_timer for race avoidance (may already be dying). */ /* Need del_timer for race avoidance (may already be dying). */
if (del_timer(&ct->timeout)) { if (del_timer(&ct->timeout)) {
ct->timeout.expires = jiffies + extra_jiffies; ct->timeout.expires = jiffies + extra_jiffies;
add_timer(&ct->timeout); add_timer(&ct->timeout);
} }
}
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
}
} }
/* Returns new sk_buff, or NULL */ /* Returns new sk_buff, or NULL */
...@@ -1422,6 +1444,18 @@ int __init ip_conntrack_init(void) ...@@ -1422,6 +1444,18 @@ int __init ip_conntrack_init(void)
/* For use by ipt_REJECT */ /* For use by ipt_REJECT */
ip_ct_attach = ip_conntrack_attach; ip_ct_attach = ip_conntrack_attach;
/* Set up fake conntrack:
- to never be deleted, not in any hashes */
atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
/* - and look it like as a confirmed connection */
set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
/* - and prepare the ctinfo field for REJECT & NAT. */
ip_conntrack_untracked.infos[IP_CT_NEW].master =
ip_conntrack_untracked.infos[IP_CT_RELATED].master =
ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master =
&ip_conntrack_untracked.ct_general;
return ret; return ret;
err_free_hash: err_free_hash:
......
...@@ -256,8 +256,8 @@ static int help(struct sk_buff *skb, ...@@ -256,8 +256,8 @@ static int help(struct sk_buff *skb,
int dir = CTINFO2DIR(ctinfo); int dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff; unsigned int matchlen, matchoff;
struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info; struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
struct ip_conntrack_expect expect, *exp = &expect; struct ip_conntrack_expect *exp;
struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info; struct ip_ct_ftp_expect *exp_ftp_info;
unsigned int i; unsigned int i;
int found = 0; int found = 0;
...@@ -347,7 +347,14 @@ static int help(struct sk_buff *skb, ...@@ -347,7 +347,14 @@ static int help(struct sk_buff *skb,
(int)matchlen, data + matchoff, (int)matchlen, data + matchoff,
matchlen, ntohl(tcph.seq) + matchoff); matchlen, ntohl(tcph.seq) + matchoff);
memset(&expect, 0, sizeof(expect)); /* Allocate expectation which will be inserted */
exp = ip_conntrack_expect_alloc();
if (exp == NULL) {
ret = NF_ACCEPT;
goto out;
}
exp_ftp_info = &exp->help.exp_ftp_info;
/* Update the ftp info */ /* Update the ftp info */
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
...@@ -389,7 +396,7 @@ static int help(struct sk_buff *skb, ...@@ -389,7 +396,7 @@ static int help(struct sk_buff *skb,
exp->expectfn = NULL; exp->expectfn = NULL;
/* Ignore failure; should only happen with NAT */ /* Ignore failure; should only happen with NAT */
ip_conntrack_expect_related(ct, &expect); ip_conntrack_expect_related(exp, ct);
ret = NF_ACCEPT; ret = NF_ACCEPT;
out: out:
UNLOCK_BH(&ip_ftp_lock); UNLOCK_BH(&ip_ftp_lock);
......
...@@ -106,8 +106,8 @@ static int help(struct sk_buff *skb, ...@@ -106,8 +106,8 @@ static int help(struct sk_buff *skb,
struct tcphdr tcph; struct tcphdr tcph;
char *data, *data_limit; char *data, *data_limit;
int dir = CTINFO2DIR(ctinfo); int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack_expect expect, *exp = &expect; struct ip_conntrack_expect *exp;
struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info; struct ip_ct_irc_expect *exp_irc_info = NULL;
u_int32_t dcc_ip; u_int32_t dcc_ip;
u_int16_t dcc_port; u_int16_t dcc_port;
...@@ -191,7 +191,11 @@ static int help(struct sk_buff *skb, ...@@ -191,7 +191,11 @@ static int help(struct sk_buff *skb,
continue; continue;
} }
memset(&expect, 0, sizeof(expect)); exp = ip_conntrack_expect_alloc();
if (exp == NULL)
goto out;
exp_irc_info = &exp->help.exp_irc_info;
/* save position of address in dcc string, /* save position of address in dcc string,
* necessary for NAT */ * necessary for NAT */
...@@ -218,7 +222,7 @@ static int help(struct sk_buff *skb, ...@@ -218,7 +222,7 @@ static int help(struct sk_buff *skb,
NIPQUAD(exp->tuple.dst.ip), NIPQUAD(exp->tuple.dst.ip),
ntohs(exp->tuple.dst.u.tcp.port)); ntohs(exp->tuple.dst.u.tcp.port));
ip_conntrack_expect_related(ct, &expect); ip_conntrack_expect_related(exp, ct);
goto out; goto out;
} /* for .. NUM_DCCPROTO */ } /* for .. NUM_DCCPROTO */
......
...@@ -178,6 +178,16 @@ static int tcp_packet(struct ip_conntrack *conntrack, ...@@ -178,6 +178,16 @@ static int tcp_packet(struct ip_conntrack *conntrack,
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0) if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
return -1; return -1;
/* If only reply is a RST, we can consider ourselves not to
have an established connection: this is a fairly common
problem case, so we can delete the conntrack
immediately. --RR */
if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
if (del_timer(&conntrack->timeout))
conntrack->timeout.function((unsigned long)conntrack);
return NF_ACCEPT;
}
WRITE_LOCK(&tcp_lock); WRITE_LOCK(&tcp_lock);
oldtcpstate = conntrack->proto.tcp.state; oldtcpstate = conntrack->proto.tcp.state;
newconntrack newconntrack
...@@ -199,29 +209,21 @@ static int tcp_packet(struct ip_conntrack *conntrack, ...@@ -199,29 +209,21 @@ static int tcp_packet(struct ip_conntrack *conntrack,
/* Poor man's window tracking: record SYN/ACK for handshake check */ /* Poor man's window tracking: record SYN/ACK for handshake check */
if (oldtcpstate == TCP_CONNTRACK_SYN_SENT if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
&& tcph.syn && tcph.ack) && tcph.syn && tcph.ack) {
conntrack->proto.tcp.handshake_ack conntrack->proto.tcp.handshake_ack
= htonl(ntohl(tcph.seq) + 1); = htonl(ntohl(tcph.seq) + 1);
goto out;
}
/* If only reply is a RST, we can consider ourselves not to /* Set ASSURED if we see valid ack in ESTABLISHED after SYN_RECV */
have an established connection: this is a fairly common
problem case, so we can delete the conntrack
immediately. --RR */
if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
WRITE_UNLOCK(&tcp_lock);
if (del_timer(&conntrack->timeout))
conntrack->timeout.function((unsigned long)conntrack);
} else {
/* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */
if (oldtcpstate == TCP_CONNTRACK_SYN_RECV if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
&& tcph.ack && !tcph.syn && tcph.ack && !tcph.syn
&& tcph.ack_seq == conntrack->proto.tcp.handshake_ack) && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
WRITE_UNLOCK(&tcp_lock); out: WRITE_UNLOCK(&tcp_lock);
ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]); ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
}
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -194,6 +194,26 @@ static unsigned int ip_confirm(unsigned int hooknum, ...@@ -194,6 +194,26 @@ static unsigned int ip_confirm(unsigned int hooknum,
return ip_conntrack_confirm(*pskb); return ip_conntrack_confirm(*pskb);
} }
static unsigned int ip_conntrack_defrag(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* Previously seen (loopback)? Ignore. Do this before
fragment check. */
if ((*pskb)->nfct)
return NF_ACCEPT;
/* Gather fragments. */
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb);
if (!*pskb)
return NF_STOLEN;
}
return NF_ACCEPT;
}
static unsigned int ip_refrag(unsigned int hooknum, static unsigned int ip_refrag(unsigned int hooknum,
struct sk_buff **pskb, struct sk_buff **pskb,
const struct net_device *in, const struct net_device *in,
...@@ -236,6 +256,14 @@ static unsigned int ip_conntrack_local(unsigned int hooknum, ...@@ -236,6 +256,14 @@ static unsigned int ip_conntrack_local(unsigned int hooknum,
/* Connection tracking may drop packets, but never alters them, so /* Connection tracking may drop packets, but never alters them, so
make it the first hook. */ make it the first hook. */
static struct nf_hook_ops ip_conntrack_defrag_ops = {
.hook = ip_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
};
static struct nf_hook_ops ip_conntrack_in_ops = { static struct nf_hook_ops ip_conntrack_in_ops = {
.hook = ip_conntrack_in, .hook = ip_conntrack_in,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -244,6 +272,14 @@ static struct nf_hook_ops ip_conntrack_in_ops = { ...@@ -244,6 +272,14 @@ static struct nf_hook_ops ip_conntrack_in_ops = {
.priority = NF_IP_PRI_CONNTRACK, .priority = NF_IP_PRI_CONNTRACK,
}; };
static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
.hook = ip_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
};
static struct nf_hook_ops ip_conntrack_local_out_ops = { static struct nf_hook_ops ip_conntrack_local_out_ops = {
.hook = ip_conntrack_local, .hook = ip_conntrack_local,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -470,10 +506,20 @@ static int init_or_cleanup(int init) ...@@ -470,10 +506,20 @@ static int init_or_cleanup(int init)
if (!proc) goto cleanup_init; if (!proc) goto cleanup_init;
proc->owner = THIS_MODULE; proc->owner = THIS_MODULE;
ret = nf_register_hook(&ip_conntrack_defrag_ops);
if (ret < 0) {
printk("ip_conntrack: can't register pre-routing defrag hook.\n");
goto cleanup_proc;
}
ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
if (ret < 0) {
printk("ip_conntrack: can't register local_out defrag hook.\n");
goto cleanup_defragops;
}
ret = nf_register_hook(&ip_conntrack_in_ops); ret = nf_register_hook(&ip_conntrack_in_ops);
if (ret < 0) { if (ret < 0) {
printk("ip_conntrack: can't register pre-routing hook.\n"); printk("ip_conntrack: can't register pre-routing hook.\n");
goto cleanup_proc; goto cleanup_defraglocalops;
} }
ret = nf_register_hook(&ip_conntrack_local_out_ops); ret = nf_register_hook(&ip_conntrack_local_out_ops);
if (ret < 0) { if (ret < 0) {
...@@ -511,6 +557,10 @@ static int init_or_cleanup(int init) ...@@ -511,6 +557,10 @@ static int init_or_cleanup(int init)
nf_unregister_hook(&ip_conntrack_local_out_ops); nf_unregister_hook(&ip_conntrack_local_out_ops);
cleanup_inops: cleanup_inops:
nf_unregister_hook(&ip_conntrack_in_ops); nf_unregister_hook(&ip_conntrack_in_ops);
cleanup_defraglocalops:
nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
cleanup_defragops:
nf_unregister_hook(&ip_conntrack_defrag_ops);
cleanup_proc: cleanup_proc:
proc_net_remove("ip_conntrack"); proc_net_remove("ip_conntrack");
cleanup_init: cleanup_init:
...@@ -591,6 +641,7 @@ EXPORT_SYMBOL(ip_ct_refresh); ...@@ -591,6 +641,7 @@ EXPORT_SYMBOL(ip_ct_refresh);
EXPORT_SYMBOL(ip_ct_find_proto); EXPORT_SYMBOL(ip_ct_find_proto);
EXPORT_SYMBOL(__ip_ct_find_proto); EXPORT_SYMBOL(__ip_ct_find_proto);
EXPORT_SYMBOL(ip_ct_find_helper); EXPORT_SYMBOL(ip_ct_find_helper);
EXPORT_SYMBOL(ip_conntrack_expect_alloc);
EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_expect_related);
EXPORT_SYMBOL(ip_conntrack_change_expect); EXPORT_SYMBOL(ip_conntrack_change_expect);
EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related);
...@@ -602,5 +653,6 @@ EXPORT_SYMBOL(ip_conntrack_htable_size); ...@@ -602,5 +653,6 @@ EXPORT_SYMBOL(ip_conntrack_htable_size);
EXPORT_SYMBOL(ip_conntrack_expect_list); EXPORT_SYMBOL(ip_conntrack_expect_list);
EXPORT_SYMBOL(ip_conntrack_lock); EXPORT_SYMBOL(ip_conntrack_lock);
EXPORT_SYMBOL(ip_conntrack_hash); EXPORT_SYMBOL(ip_conntrack_hash);
EXPORT_SYMBOL(ip_conntrack_untracked);
EXPORT_SYMBOL_GPL(ip_conntrack_find_get); EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
EXPORT_SYMBOL_GPL(ip_conntrack_put); EXPORT_SYMBOL_GPL(ip_conntrack_put);
...@@ -44,7 +44,7 @@ static int tftp_help(struct sk_buff *skb, ...@@ -44,7 +44,7 @@ static int tftp_help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo)
{ {
struct tftphdr tftph; struct tftphdr tftph;
struct ip_conntrack_expect exp; struct ip_conntrack_expect *exp;
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr), if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
&tftph, sizeof(tftph)) != 0) &tftph, sizeof(tftph)) != 0)
...@@ -57,19 +57,22 @@ static int tftp_help(struct sk_buff *skb, ...@@ -57,19 +57,22 @@ static int tftp_help(struct sk_buff *skb,
DEBUGP(""); DEBUGP("");
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
memset(&exp, 0, sizeof(exp));
exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; exp = ip_conntrack_expect_alloc();
exp.mask.src.ip = 0xffffffff; if (exp == NULL)
exp.mask.dst.ip = 0xffffffff; return NF_ACCEPT;
exp.mask.dst.u.udp.port = 0xffff;
exp.mask.dst.protonum = 0xffff; exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
exp.expectfn = NULL; exp->mask.src.ip = 0xffffffff;
exp->mask.dst.ip = 0xffffffff;
exp->mask.dst.u.udp.port = 0xffff;
exp->mask.dst.protonum = 0xffff;
exp->expectfn = NULL;
DEBUGP("expect: "); DEBUGP("expect: ");
DUMP_TUPLE(&exp.tuple); DUMP_TUPLE(&exp->tuple);
DUMP_TUPLE(&exp.mask); DUMP_TUPLE(&exp->mask);
ip_conntrack_expect_related(ct, &exp); ip_conntrack_expect_related(exp, ct);
break; break;
case TFTP_OPCODE_DATA: case TFTP_OPCODE_DATA:
case TFTP_OPCODE_ACK: case TFTP_OPCODE_ACK:
......
...@@ -1017,6 +1017,10 @@ int __init ip_nat_init(void) ...@@ -1017,6 +1017,10 @@ int __init ip_nat_init(void)
IP_NF_ASSERT(ip_conntrack_destroyed == NULL); IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
/* Initialize fake conntrack so that NAT will skip it */
ip_conntrack_untracked.nat.info.initialized |=
(1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
return 0; return 0;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <net/tcp.h> #include <net/tcp.h>
#include <net/route.h> #include <net/route.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h> #include <linux/netfilter_ipv4/ipt_LOG.h>
...@@ -26,6 +27,10 @@ MODULE_LICENSE("GPL"); ...@@ -26,6 +27,10 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables syslog logging module"); 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 #if 0
#define DEBUGP printk #define DEBUGP printk
#else #else
...@@ -324,28 +329,25 @@ static void dump_packet(const struct ipt_log_info *info, ...@@ -324,28 +329,25 @@ static void dump_packet(const struct ipt_log_info *info,
/* maxlen = 230+ 91 + 230 + 252 = 803 */ /* maxlen = 230+ 91 + 230 + 252 = 803 */
} }
static unsigned int static void
ipt_log_target(struct sk_buff **pskb, ipt_log_packet(unsigned int hooknum,
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,
unsigned int hooknum, const struct ipt_log_info *loginfo,
const void *targinfo, const char *level_string,
void *userinfo) 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); spin_lock_bh(&log_lock);
printk(level_string); printk(level_string);
printk("%sIN=%s OUT=%s ", printk("%sIN=%s OUT=%s ",
loginfo->prefix, prefix == NULL ? loginfo->prefix : prefix,
in ? in->name : "", in ? in->name : "",
out ? out->name : ""); out ? out->name : "");
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
if ((*pskb)->nf_bridge) { if (skb->nf_bridge) {
struct net_device *physindev = (*pskb)->nf_bridge->physindev; struct net_device *physindev = skb->nf_bridge->physindev;
struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev; struct net_device *physoutdev = skb->nf_bridge->physoutdev;
if (physindev && in != physindev) if (physindev && in != physindev)
printk("PHYSIN=%s ", physindev->name); printk("PHYSIN=%s ", physindev->name);
...@@ -357,25 +359,56 @@ ipt_log_target(struct sk_buff **pskb, ...@@ -357,25 +359,56 @@ ipt_log_target(struct sk_buff **pskb,
if (in && !out) { if (in && !out) {
/* MAC logging for input chain only. */ /* MAC logging for input chain only. */
printk("MAC="); printk("MAC=");
if ((*pskb)->dev && (*pskb)->dev->hard_header_len if (skb->dev && skb->dev->hard_header_len
&& (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) { && skb->mac.raw != (void*)skb->nh.iph) {
int i; int i;
unsigned char *p = (*pskb)->mac.raw; unsigned char *p = skb->mac.raw;
for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) for (i = 0; i < skb->dev->hard_header_len; i++,p++)
printk("%02x%c", *p, printk("%02x%c", *p,
i==(*pskb)->dev->hard_header_len - 1 i==skb->dev->hard_header_len - 1
? ' ':':'); ? ' ':':');
} else } else
printk(" "); printk(" ");
} }
dump_packet(loginfo, *pskb, 0); dump_packet(loginfo, skb, 0);
printk("\n"); printk("\n");
spin_unlock_bh(&log_lock); 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; 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, static int ipt_log_checkentry(const char *tablename,
const struct ipt_entry *e, const struct ipt_entry *e,
void *targinfo, void *targinfo,
...@@ -413,11 +446,18 @@ static struct ipt_target ipt_log_reg = { ...@@ -413,11 +446,18 @@ static struct ipt_target ipt_log_reg = {
static int __init init(void) 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) static void __exit fini(void)
{ {
if (nflog)
nf_log_unregister(PF_INET, &ipt_logfn);
ipt_unregister_target(&ipt_log_reg); ipt_unregister_target(&ipt_log_reg);
} }
......
/* This is a module which is used for setting up fake conntracks
* on packets so that they are not seen by the conntrack/NAT code.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
static unsigned int
target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
/* Previously seen (loopback)? Ignore. */
if ((*pskb)->nfct != NULL)
return IPT_CONTINUE;
/* Attach fake conntrack entry.
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
(*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
nf_conntrack_get((*pskb)->nfct);
return IPT_CONTINUE;
}
static int
checkentry(const char *tablename,
const struct ipt_entry *e,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
if (targinfosize != 0) {
printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
targinfosize);
return 0;
}
if (strcmp(tablename, "raw") != 0) {
printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
return 0;
}
return 1;
}
static struct ipt_target ipt_notrack_reg = {
.name = "NOTRACK",
.target = target,
.checkentry = checkentry,
.me = THIS_MODULE
};
static int __init init(void)
{
if (ipt_register_target(&ipt_notrack_reg))
return -EINVAL;
return 0;
}
static void __exit fini(void)
{
ipt_unregister_target(&ipt_notrack_reg);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h> #include <linux/netfilter_ipv4/ipt_ULOG.h>
#include <linux/netfilter_ipv4/lockhelp.h> #include <linux/netfilter_ipv4/lockhelp.h>
...@@ -80,6 +81,10 @@ static unsigned int flushtimeout = 10 * HZ; ...@@ -80,6 +81,10 @@ static unsigned int flushtimeout = 10 * HZ;
MODULE_PARM(flushtimeout, "i"); MODULE_PARM(flushtimeout, "i");
MODULE_PARM_DESC(flushtimeout, "buffer flush timeout"); 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 */ /* global data structures */
typedef struct { typedef struct {
...@@ -157,17 +162,17 @@ struct sk_buff *ulog_alloc_skb(unsigned int size) ...@@ -157,17 +162,17 @@ struct sk_buff *ulog_alloc_skb(unsigned int size)
return skb; return skb;
} }
static unsigned int ipt_ulog_target(struct sk_buff **pskb, static void ipt_ulog_packet(unsigned int hooknum,
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,
unsigned int hooknum, const struct ipt_ulog_info *loginfo,
const void *targinfo, void *userinfo) const char *prefix)
{ {
ulog_buff_t *ub; ulog_buff_t *ub;
ulog_packet_msg_t *pm; ulog_packet_msg_t *pm;
size_t size, copy_len; size_t size, copy_len;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
/* ffs == find first bit set, necessary because userspace /* ffs == find first bit set, necessary because userspace
* is already shifting groupnumber, but we need unshifted. * is already shifting groupnumber, but we need unshifted.
...@@ -176,8 +181,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -176,8 +181,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
/* calculate the size of the skb needed */ /* calculate the size of the skb needed */
if ((loginfo->copy_range == 0) || if ((loginfo->copy_range == 0) ||
(loginfo->copy_range > (*pskb)->len)) { (loginfo->copy_range > skb->len)) {
copy_len = (*pskb)->len; copy_len = skb->len;
} else { } else {
copy_len = loginfo->copy_range; copy_len = loginfo->copy_range;
} }
...@@ -214,19 +219,21 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -214,19 +219,21 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
/* copy hook, prefix, timestamp, payload, etc. */ /* copy hook, prefix, timestamp, payload, etc. */
pm->data_len = copy_len; pm->data_len = copy_len;
pm->timestamp_sec = (*pskb)->stamp.tv_sec; pm->timestamp_sec = skb->stamp.tv_sec;
pm->timestamp_usec = (*pskb)->stamp.tv_usec; pm->timestamp_usec = skb->stamp.tv_usec;
pm->mark = (*pskb)->nfmark; pm->mark = skb->nfmark;
pm->hook = hooknum; 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)); strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
else else
*(pm->prefix) = '\0'; *(pm->prefix) = '\0';
if (in && in->hard_header_len > 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) { && 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; pm->mac_len = in->hard_header_len;
} else } else
pm->mac_len = 0; pm->mac_len = 0;
...@@ -241,8 +248,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -241,8 +248,8 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
else else
pm->outdev_name[0] = '\0'; pm->outdev_name[0] = '\0';
/* copy_len <= (*pskb)->len, so can't fail. */ /* copy_len <= skb->len, so can't fail. */
if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0) if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
BUG(); BUG();
/* check if we are building multi-part messages */ /* check if we are building multi-part messages */
...@@ -266,8 +273,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -266,8 +273,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
UNLOCK_BH(&ulog_lock); UNLOCK_BH(&ulog_lock);
return IPT_CONTINUE; return;
nlmsg_failure: nlmsg_failure:
PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
...@@ -276,10 +282,37 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -276,10 +282,37 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
PRINTR("ipt_ULOG: Error building netlink message\n"); PRINTR("ipt_ULOG: Error building netlink message\n");
UNLOCK_BH(&ulog_lock); UNLOCK_BH(&ulog_lock);
}
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; 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, static int ipt_ulog_checkentry(const char *tablename,
const struct ipt_entry *e, const struct ipt_entry *e,
void *targinfo, void *targinfo,
...@@ -341,6 +374,8 @@ static int __init init(void) ...@@ -341,6 +374,8 @@ static int __init init(void)
sock_release(nflognl->sk_socket); sock_release(nflognl->sk_socket);
return -EINVAL; return -EINVAL;
} }
if (nflog)
nf_log_register(PF_INET, &ipt_logfn);
return 0; return 0;
} }
...@@ -352,6 +387,8 @@ static void __exit fini(void) ...@@ -352,6 +387,8 @@ static void __exit fini(void)
DEBUGP("ipt_ULOG: cleanup_module\n"); DEBUGP("ipt_ULOG: cleanup_module\n");
if (nflog)
nf_log_unregister(PF_INET, &ipt_logfn);
ipt_unregister_target(&ipt_ulog_reg); ipt_unregister_target(&ipt_ulog_reg);
sock_release(nflognl->sk_socket); sock_release(nflognl->sk_socket);
......
...@@ -35,7 +35,9 @@ match(const struct sk_buff *skb, ...@@ -35,7 +35,9 @@ match(const struct sk_buff *skb,
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
if (ct) if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
statebit = IPT_CONNTRACK_STATE_UNTRACKED;
else if (ct)
statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
else else
statebit = IPT_CONNTRACK_STATE_INVALID; statebit = IPT_CONNTRACK_STATE_INVALID;
......
...@@ -30,7 +30,9 @@ match(const struct sk_buff *skb, ...@@ -30,7 +30,9 @@ match(const struct sk_buff *skb,
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
unsigned int statebit; unsigned int statebit;
if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
statebit = IPT_STATE_UNTRACKED;
else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
statebit = IPT_STATE_INVALID; statebit = IPT_STATE_INVALID;
else else
statebit = IPT_STATE_BIT(ctinfo); statebit = IPT_STATE_BIT(ctinfo);
......
/*
* 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
*
* Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*/
#include <linux/module.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
/* Standard entry. */
struct ipt_standard
{
struct ipt_entry entry;
struct ipt_standard_target target;
};
struct ipt_error_target
{
struct ipt_entry_target target;
char errorname[IPT_FUNCTION_MAXNAMELEN];
};
struct ipt_error
{
struct ipt_entry entry;
struct ipt_error_target target;
};
static struct
{
struct ipt_replace repl;
struct ipt_standard entries[2];
struct ipt_error term;
} initial_table __initdata
= { { "raw", RAW_VALID_HOOKS, 3,
sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
{ [NF_IP_PRE_ROUTING] 0,
[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
{ [NF_IP_PRE_ROUTING] 0,
[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
0, NULL, { } },
{
/* PRE_ROUTING */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } }
},
/* ERROR */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_error),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
{ } },
"ERROR"
}
}
};
static struct ipt_table packet_raw = {
.name = "raw",
.table = &initial_table.repl,
.valid_hooks = RAW_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
.me = THIS_MODULE
};
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
}
/* 'raw' is the very first table. */
static struct nf_hook_ops ipt_ops[] = {
{
.hook = ipt_hook,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_RAW
},
{
.hook = ipt_hook,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_RAW
},
};
static int __init init(void)
{
int ret;
/* Register table */
ret = ipt_register_table(&packet_raw);
if (ret < 0)
return ret;
/* Register hooks */
ret = nf_register_hook(&ipt_ops[0]);
if (ret < 0)
goto cleanup_table;
ret = nf_register_hook(&ipt_ops[1]);
if (ret < 0)
goto cleanup_hook0;
return ret;
cleanup_hook0:
nf_unregister_hook(&ipt_ops[0]);
cleanup_table:
ipt_unregister_table(&packet_raw);
return ret;
}
static void __exit fini(void)
{
unsigned int i;
for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
nf_unregister_hook(&ipt_ops[i]);
ipt_unregister_table(&packet_raw);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
...@@ -218,5 +218,17 @@ config IP6_NF_TARGET_MARK ...@@ -218,5 +218,17 @@ config IP6_NF_TARGET_MARK
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
#dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
config IP6_NF_RAW
tristate 'raw table support (required for TRACE)'
depends on IP6_NF_IPTABLES
help
This option adds a `raw' table to ip6tables. This table is the very
first in the netfilter framework and hooks in at the PREROUTING
and OUTPUT chains.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
help
endmenu endmenu
...@@ -21,4 +21,5 @@ obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o ...@@ -21,4 +21,5 @@ obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
...@@ -18,12 +18,17 @@ ...@@ -18,12 +18,17 @@
#include <net/udp.h> #include <net/udp.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
MODULE_DESCRIPTION("IP6 tables LOG target module"); MODULE_DESCRIPTION("IP6 tables LOG target module");
MODULE_LICENSE("GPL"); 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; struct in_device;
#include <net/route.h> #include <net/route.h>
#include <linux/netfilter_ipv6/ip6t_LOG.h> #include <linux/netfilter_ipv6/ip6t_LOG.h>
...@@ -265,40 +270,38 @@ static void dump_packet(const struct ip6t_log_info *info, ...@@ -265,40 +270,38 @@ static void dump_packet(const struct ip6t_log_info *info,
} }
} }
static unsigned int static void
ip6t_log_target(struct sk_buff **pskb, ip6t_log_packet(unsigned int hooknum,
unsigned int hooknum, 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 void *targinfo, const struct ip6t_log_info *loginfo,
void *userinfo) const char *level_string,
const char *prefix)
{ {
struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h; struct ipv6hdr *ipv6h = skb->nh.ipv6h;
const struct ip6t_log_info *loginfo = targinfo;
char level_string[4] = "< >";
level_string[1] = '0' + (loginfo->level % 8);
spin_lock_bh(&log_lock); spin_lock_bh(&log_lock);
printk(level_string); printk(level_string);
printk("%sIN=%s OUT=%s ", printk("%sIN=%s OUT=%s ",
loginfo->prefix, prefix == NULL ? loginfo->prefix : prefix,
in ? in->name : "", in ? in->name : "",
out ? out->name : ""); out ? out->name : "");
if (in && !out) { if (in && !out) {
/* MAC logging for input chain only. */ /* MAC logging for input chain only. */
printk("MAC="); printk("MAC=");
if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) { if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
if ((*pskb)->dev->type != ARPHRD_SIT){ if (skb->dev->type != ARPHRD_SIT){
int i; int i;
unsigned char *p = (*pskb)->mac.raw; unsigned char *p = skb->mac.raw;
for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) for (i = 0; i < skb->dev->hard_header_len; i++,p++)
printk("%02x%c", *p, printk("%02x%c", *p,
i==(*pskb)->dev->hard_header_len - 1 i==skb->dev->hard_header_len - 1
? ' ':':'); ? ' ':':');
} else { } else {
int i; int i;
unsigned char *p = (*pskb)->mac.raw; unsigned char *p = skb->mac.raw;
if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){ if ( p - (ETH_ALEN*2+2) > skb->head ){
p -= (ETH_ALEN+2); p -= (ETH_ALEN+2);
for (i = 0; i < (ETH_ALEN); i++,p++) for (i = 0; i < (ETH_ALEN); i++,p++)
printk("%02x%s", *p, printk("%02x%s", *p,
...@@ -309,10 +312,10 @@ ip6t_log_target(struct sk_buff **pskb, ...@@ -309,10 +312,10 @@ ip6t_log_target(struct sk_buff **pskb,
i == ETH_ALEN-1 ? ' ' : ':'); i == ETH_ALEN-1 ? ' ' : ':');
} }
if (((*pskb)->dev->addr_len == 4) && if ((skb->dev->addr_len == 4) &&
(*pskb)->dev->hard_header_len > 20){ skb->dev->hard_header_len > 20){
printk("TUNNEL="); printk("TUNNEL=");
p = (*pskb)->mac.raw + 12; p = skb->mac.raw + 12;
for (i = 0; i < 4; i++,p++) for (i = 0; i < 4; i++,p++)
printk("%3d%s", *p, printk("%3d%s", *p,
i == 3 ? "->" : "."); i == 3 ? "->" : ".");
...@@ -328,10 +331,41 @@ ip6t_log_target(struct sk_buff **pskb, ...@@ -328,10 +331,41 @@ ip6t_log_target(struct sk_buff **pskb,
dump_packet(loginfo, ipv6h, 1); dump_packet(loginfo, ipv6h, 1);
printk("\n"); printk("\n");
spin_unlock_bh(&log_lock); 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; 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, static int ip6t_log_checkentry(const char *tablename,
const struct ip6t_entry *e, const struct ip6t_entry *e,
void *targinfo, void *targinfo,
...@@ -360,20 +394,27 @@ static int ip6t_log_checkentry(const char *tablename, ...@@ -360,20 +394,27 @@ static int ip6t_log_checkentry(const char *tablename,
return 1; return 1;
} }
static struct ip6t_target ip6t_log_reg static struct ip6t_target ip6t_log_reg = {
= { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL, .name = "LOG",
THIS_MODULE }; .target = ip6t_log_target,
.checkentry = ip6t_log_checkentry,
.me = THIS_MODULE,
};
static int __init init(void) static int __init init(void)
{ {
if (ip6t_register_target(&ip6t_log_reg)) if (ip6t_register_target(&ip6t_log_reg))
return -EINVAL; return -EINVAL;
if (nflog)
nf_log_register(PF_INET6, &ip6t_logfn);
return 0; return 0;
} }
static void __exit fini(void) static void __exit fini(void)
{ {
if (nflog)
nf_log_unregister(PF_INET6, &ip6t_logfn);
ip6t_unregister_target(&ip6t_log_reg); ip6t_unregister_target(&ip6t_log_reg);
} }
......
/*
* IPv6 raw table, a port of the IPv4 raw table to IPv6
*
* Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*/
#include <linux/module.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
#if 0
#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
#else
#define DEBUGP(x, args...)
#endif
/* Standard entry. */
struct ip6t_standard
{
struct ip6t_entry entry;
struct ip6t_standard_target target;
};
struct ip6t_error_target
{
struct ip6t_entry_target target;
char errorname[IP6T_FUNCTION_MAXNAMELEN];
};
struct ip6t_error
{
struct ip6t_entry entry;
struct ip6t_error_target target;
};
static struct
{
struct ip6t_replace repl;
struct ip6t_standard entries[2];
struct ip6t_error term;
} initial_table __initdata
= { { "raw", RAW_VALID_HOOKS, 3,
sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
{ [NF_IP6_PRE_ROUTING] 0,
[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
{ [NF_IP6_PRE_ROUTING] 0,
[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
0, NULL, { } },
{
/* PRE_ROUTING */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
},
/* ERROR */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_error),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
{ } },
"ERROR"
}
}
};
static struct ip6t_table packet_raw = {
.name = "raw",
.table = &initial_table.repl,
.valid_hooks = RAW_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
.me = THIS_MODULE
};
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
}
static struct nf_hook_ops ip6t_ops[] = {
{
.hook = ip6t_hook,
.pf = PF_INET6,
.hooknum = NF_IP6_PRE_ROUTING,
.priority = NF_IP6_PRI_FIRST
},
{
.hook = ip6t_hook,
.pf = PF_INET6,
.hooknum = NF_IP6_LOCAL_OUT,
.priority = NF_IP6_PRI_FIRST
},
};
static int __init init(void)
{
int ret;
/* Register table */
ret = ip6t_register_table(&packet_raw);
if (ret < 0)
return ret;
/* Register hooks */
ret = nf_register_hook(&ip6t_ops[0]);
if (ret < 0)
goto cleanup_table;
ret = nf_register_hook(&ip6t_ops[1]);
if (ret < 0)
goto cleanup_hook0;
return ret;
cleanup_hook0:
nf_unregister_hook(&ip6t_ops[0]);
cleanup_table:
ip6t_unregister_table(&packet_raw);
return ret;
}
static void __exit fini(void)
{
unsigned int i;
for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
nf_unregister_hook(&ip6t_ops[i]);
ip6t_unregister_table(&packet_raw);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
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