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);
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).
......
......@@ -51,6 +51,8 @@
enum nf_ip_hook_priorities {
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_CONNTRACK = -200,
NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
......
......@@ -252,6 +252,9 @@ extern void ip_ct_refresh(struct ip_conntrack *ct,
/* Call me when a conntrack is destroyed. */
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 */
struct sk_buff *
ip_ct_gather_frags(struct sk_buff *skb);
......
......@@ -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);
/* 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 */
extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
struct ip_conntrack_expect *exp);
extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp,
struct ip_conntrack *related_to);
extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
struct ip_conntrack_tuple *newtuple);
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 @@
#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
......
......@@ -10,6 +10,7 @@
#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
/* flags, invflags: */
#define IPT_CONNTRACK_STATE 0x01
......
......@@ -4,6 +4,8 @@
#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
#define IPT_STATE_INVALID (1 << 0)
#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
struct ipt_state_info
{
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 @@
*
* 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,
......
......@@ -579,5 +579,29 @@ config IP_NF_COMPAT_IPFWADM
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
......@@ -38,6 +38,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches
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
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
# generic ARP tables
obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
......
......@@ -46,10 +46,11 @@ static DECLARE_LOCK(amanda_buffer_lock);
static int help(struct sk_buff *skb,
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;
char *data, *data_limit, *tmp;
unsigned int dataoff, i;
u_int16_t port, len;
/* Only look at packets from the Amanda server */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
......@@ -79,33 +80,40 @@ static int help(struct sk_buff *skb,
goto out;
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. */
if ((tmp = strchr(data, '\n')))
*tmp = '\0';
exp_amanda_info = &exp.help.exp_amanda_info;
for (i = 0; i < ARRAY_SIZE(conns); i++) {
char *match = strstr(data, conns[i]);
if (!match)
continue;
tmp = data = match + strlen(conns[i]);
exp_amanda_info->offset = data - amanda_buffer;
exp_amanda_info->port = simple_strtoul(data, &data, 10);
exp_amanda_info->len = data - tmp;
if (exp_amanda_info->port == 0 || exp_amanda_info->len > 5)
port = simple_strtoul(data, &data, 10);
len = data - tmp;
if (port == 0 || len > 5)
break;
exp.tuple.dst.u.tcp.port = htons(exp_amanda_info->port);
ip_conntrack_expect_related(ct, &exp);
exp = ip_conntrack_expect_alloc();
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:
......
......@@ -67,6 +67,7 @@ int ip_conntrack_max;
static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
struct list_head *ip_conntrack_hash;
static kmem_cache_t *ip_conntrack_cachep;
struct ip_conntrack ip_conntrack_untracked;
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
......@@ -794,6 +795,15 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
int set_reply;
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 */
(*pskb)->nfcache |= NFC_UNKNOWN;
......@@ -812,18 +822,10 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
}
#endif
/* Previously seen (loopback)? Ignore. Do this before
fragment check. */
/* Previously seen (loopback or untracked)? Ignore. */
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;
}
proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
/* It may be an icmp error... */
......@@ -917,11 +919,55 @@ static void expectation_timed_out(unsigned long ul_expect)
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. */
int ip_conntrack_expect_related(struct ip_conntrack *related_to,
struct ip_conntrack_expect *expect)
int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
struct ip_conntrack *related_to)
{
struct ip_conntrack_expect *old, *new;
struct ip_conntrack_expect *old;
int ret = 0;
WRITE_LOCK(&ip_conntrack_lock);
......@@ -943,7 +989,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
if (related_to->helper->timeout) {
if (!del_timer(&old->timeout)) {
/* expectation is dying. Fall through */
old = NULL;
goto out;
} else {
old->timeout.expires = jiffies +
related_to->helper->timeout * HZ;
......@@ -951,10 +997,10 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
}
}
if (old) {
WRITE_UNLOCK(&ip_conntrack_lock);
return -EEXIST;
}
WRITE_UNLOCK(&ip_conntrack_lock);
kfree(expect);
return -EEXIST;
} else if (related_to->helper->max_expected &&
related_to->expecting >= related_to->helper->max_expected) {
struct list_head *cur_item;
......@@ -971,6 +1017,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
related_to->helper->name,
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
kfree(expect);
return -EPERM;
}
DEBUGP("ip_conntrack: max number of expected "
......@@ -1010,37 +1057,12 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
&expect->mask)) {
WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_related: busy!\n");
kfree(expect);
return -EBUSY;
}
new = (struct ip_conntrack_expect *)
kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
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);
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++;
out: ip_conntrack_expect_insert(expect, related_to);
WRITE_UNLOCK(&ip_conntrack_lock);
......@@ -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);
WRITE_LOCK(&ip_conntrack_lock);
/* If not in hash table, timer will not be active yet */
if (!is_confirmed(ct))
ct->timeout.expires = extra_jiffies;
else {
WRITE_LOCK(&ip_conntrack_lock);
/* Need del_timer for race avoidance (may already be dying). */
if (del_timer(&ct->timeout)) {
ct->timeout.expires = jiffies + extra_jiffies;
add_timer(&ct->timeout);
}
WRITE_UNLOCK(&ip_conntrack_lock);
}
WRITE_UNLOCK(&ip_conntrack_lock);
}
/* Returns new sk_buff, or NULL */
......@@ -1422,6 +1444,18 @@ int __init ip_conntrack_init(void)
/* For use by ipt_REJECT */
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;
err_free_hash:
......
......@@ -256,8 +256,8 @@ static int help(struct sk_buff *skb,
int dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff;
struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
struct ip_conntrack_expect expect, *exp = &expect;
struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
struct ip_conntrack_expect *exp;
struct ip_ct_ftp_expect *exp_ftp_info;
unsigned int i;
int found = 0;
......@@ -346,8 +346,15 @@ static int help(struct sk_buff *skb,
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
(int)matchlen, data + 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 */
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
......@@ -389,7 +396,7 @@ static int help(struct sk_buff *skb,
exp->expectfn = NULL;
/* Ignore failure; should only happen with NAT */
ip_conntrack_expect_related(ct, &expect);
ip_conntrack_expect_related(exp, ct);
ret = NF_ACCEPT;
out:
UNLOCK_BH(&ip_ftp_lock);
......
......@@ -106,8 +106,8 @@ static int help(struct sk_buff *skb,
struct tcphdr tcph;
char *data, *data_limit;
int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack_expect expect, *exp = &expect;
struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
struct ip_conntrack_expect *exp;
struct ip_ct_irc_expect *exp_irc_info = NULL;
u_int32_t dcc_ip;
u_int16_t dcc_port;
......@@ -190,8 +190,12 @@ static int help(struct sk_buff *skb,
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,
* necessary for NAT */
......@@ -218,7 +222,7 @@ static int help(struct sk_buff *skb,
NIPQUAD(exp->tuple.dst.ip),
ntohs(exp->tuple.dst.u.tcp.port));
ip_conntrack_expect_related(ct, &expect);
ip_conntrack_expect_related(exp, ct);
goto out;
} /* for .. NUM_DCCPROTO */
......
......@@ -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)
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);
oldtcpstate = conntrack->proto.tcp.state;
newconntrack
......@@ -199,29 +209,21 @@ static int tcp_packet(struct ip_conntrack *conntrack,
/* Poor man's window tracking: record SYN/ACK for handshake check */
if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
&& tcph.syn && tcph.ack)
&& tcph.syn && tcph.ack) {
conntrack->proto.tcp.handshake_ack
= htonl(ntohl(tcph.seq) + 1);
goto out;
}
/* 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) {
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
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
&& tcph.ack && !tcph.syn
&& tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
set_bit(IPS_ASSURED_BIT, &conntrack->status);
/* Set ASSURED if we see valid ack in ESTABLISHED after SYN_RECV */
if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
&& tcph.ack && !tcph.syn
&& tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
set_bit(IPS_ASSURED_BIT, &conntrack->status);
WRITE_UNLOCK(&tcp_lock);
ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
}
out: WRITE_UNLOCK(&tcp_lock);
ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
return NF_ACCEPT;
}
......
......@@ -194,6 +194,26 @@ static unsigned int ip_confirm(unsigned int hooknum,
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,
struct sk_buff **pskb,
const struct net_device *in,
......@@ -236,6 +256,14 @@ static unsigned int ip_conntrack_local(unsigned int hooknum,
/* Connection tracking may drop packets, but never alters them, so
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 = {
.hook = ip_conntrack_in,
.owner = THIS_MODULE,
......@@ -244,6 +272,14 @@ static struct nf_hook_ops ip_conntrack_in_ops = {
.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 = {
.hook = ip_conntrack_local,
.owner = THIS_MODULE,
......@@ -470,10 +506,20 @@ static int init_or_cleanup(int init)
if (!proc) goto cleanup_init;
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);
if (ret < 0) {
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);
if (ret < 0) {
......@@ -511,6 +557,10 @@ static int init_or_cleanup(int init)
nf_unregister_hook(&ip_conntrack_local_out_ops);
cleanup_inops:
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:
proc_net_remove("ip_conntrack");
cleanup_init:
......@@ -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_helper);
EXPORT_SYMBOL(ip_conntrack_expect_alloc);
EXPORT_SYMBOL(ip_conntrack_expect_related);
EXPORT_SYMBOL(ip_conntrack_change_expect);
EXPORT_SYMBOL(ip_conntrack_unexpect_related);
......@@ -602,5 +653,6 @@ EXPORT_SYMBOL(ip_conntrack_htable_size);
EXPORT_SYMBOL(ip_conntrack_expect_list);
EXPORT_SYMBOL(ip_conntrack_lock);
EXPORT_SYMBOL(ip_conntrack_hash);
EXPORT_SYMBOL(ip_conntrack_untracked);
EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
EXPORT_SYMBOL_GPL(ip_conntrack_put);
......@@ -44,7 +44,7 @@ static int tftp_help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo)
{
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),
&tftph, sizeof(tftph)) != 0)
......@@ -57,19 +57,22 @@ static int tftp_help(struct sk_buff *skb,
DEBUGP("");
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].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.mask.src.ip = 0xffffffff;
exp.mask.dst.ip = 0xffffffff;
exp.mask.dst.u.udp.port = 0xffff;
exp.mask.dst.protonum = 0xffff;
exp.expectfn = NULL;
exp = ip_conntrack_expect_alloc();
if (exp == NULL)
return NF_ACCEPT;
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
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: ");
DUMP_TUPLE(&exp.tuple);
DUMP_TUPLE(&exp.mask);
ip_conntrack_expect_related(ct, &exp);
DUMP_TUPLE(&exp->tuple);
DUMP_TUPLE(&exp->mask);
ip_conntrack_expect_related(exp, ct);
break;
case TFTP_OPCODE_DATA:
case TFTP_OPCODE_ACK:
......
......@@ -1016,6 +1016,10 @@ int __init ip_nat_init(void)
/* FIXME: Man, this is a hack. <SIGH> */
IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
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;
}
......
......@@ -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);
}
......
/* 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 @@
#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);
......
......@@ -35,11 +35,13 @@ match(const struct sk_buff *skb,
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
if (ct)
statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
else
statebit = IPT_CONNTRACK_STATE_INVALID;
if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
statebit = IPT_CONNTRACK_STATE_UNTRACKED;
else if (ct)
statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
else
statebit = IPT_CONNTRACK_STATE_INVALID;
if(sinfo->flags & IPT_CONNTRACK_STATE) {
if (ct) {
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
......
......@@ -30,7 +30,9 @@ match(const struct sk_buff *skb,
enum ip_conntrack_info ctinfo;
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;
else
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
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
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
......@@ -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_QUEUE) += ip6_queue.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
......@@ -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);
}
......
/*
* 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