Commit ba9dda3a authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by David S. Miller

[NETFILTER]: x_tables: add TRACE target

The TRACE target can be used to follow IP and IPv6 packets through
the ruleset.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick NcHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b50b8a3
...@@ -227,6 +227,7 @@ typedef unsigned char *sk_buff_data_t; ...@@ -227,6 +227,7 @@ typedef unsigned char *sk_buff_data_t;
* @mark: Generic packet mark * @mark: Generic packet mark
* @nfct: Associated connection, if any * @nfct: Associated connection, if any
* @ipvs_property: skbuff is owned by ipvs * @ipvs_property: skbuff is owned by ipvs
* @nf_trace: netfilter packet trace flag
* @nfctinfo: Relationship of this skb to the connection * @nfctinfo: Relationship of this skb to the connection
* @nfct_reasm: netfilter conntrack re-assembly pointer * @nfct_reasm: netfilter conntrack re-assembly pointer
* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
...@@ -278,7 +279,8 @@ struct sk_buff { ...@@ -278,7 +279,8 @@ struct sk_buff {
nfctinfo:3; nfctinfo:3;
__u8 pkt_type:3, __u8 pkt_type:3,
fclone:2, fclone:2,
ipvs_property:1; ipvs_property:1,
nf_trace:1;
__be16 protocol; __be16 protocol;
void (*destructor)(struct sk_buff *skb); void (*destructor)(struct sk_buff *skb);
......
...@@ -428,6 +428,10 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) ...@@ -428,6 +428,10 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
n->destructor = NULL; n->destructor = NULL;
C(mark); C(mark);
__nf_copy(n, skb); __nf_copy(n, skb);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
C(nf_trace);
#endif
#ifdef CONFIG_NET_SCHED #ifdef CONFIG_NET_SCHED
C(tc_index); C(tc_index);
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
...@@ -485,6 +489,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) ...@@ -485,6 +489,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->destructor = NULL; new->destructor = NULL;
new->mark = old->mark; new->mark = old->mark;
__nf_copy(new, old); __nf_copy(new, old);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
new->nf_trace = old->nf_trace;
#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
new->ipvs_property = old->ipvs_property; new->ipvs_property = old->ipvs_property;
#endif #endif
......
...@@ -399,6 +399,10 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) ...@@ -399,6 +399,10 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index; to->tc_index = from->tc_index;
#endif #endif
nf_copy(to, from); nf_copy(to, from);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
to->nf_trace = from->nf_trace;
#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
to->ipvs_property = from->ipvs_property; to->ipvs_property = from->ipvs_property;
#endif #endif
......
...@@ -204,6 +204,112 @@ get_entry(void *base, unsigned int offset) ...@@ -204,6 +204,112 @@ get_entry(void *base, unsigned int offset)
return (struct ipt_entry *)(base + offset); return (struct ipt_entry *)(base + offset);
} }
/* All zeroes == unconditional rule. */
static inline int
unconditional(const struct ipt_ip *ip)
{
unsigned int i;
for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
if (((__u32 *)ip)[i])
return 0;
return 1;
}
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
static const char *hooknames[] = {
[NF_IP_PRE_ROUTING] = "PREROUTING",
[NF_IP_LOCAL_IN] = "INPUT",
[NF_IP_FORWARD] = "FORWARD",
[NF_IP_LOCAL_OUT] = "OUTPUT",
[NF_IP_POST_ROUTING] = "POSTROUTING",
};
enum nf_ip_trace_comments {
NF_IP_TRACE_COMMENT_RULE,
NF_IP_TRACE_COMMENT_RETURN,
NF_IP_TRACE_COMMENT_POLICY,
};
static const char *comments[] = {
[NF_IP_TRACE_COMMENT_RULE] = "rule",
[NF_IP_TRACE_COMMENT_RETURN] = "return",
[NF_IP_TRACE_COMMENT_POLICY] = "policy",
};
static struct nf_loginfo trace_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
.log = {
.level = 4,
.logflags = NF_LOG_MASK,
},
},
};
static inline int
get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
char *hookname, char **chainname,
char **comment, unsigned int *rulenum)
{
struct ipt_standard_target *t = (void *)ipt_get_target(s);
if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
*chainname = t->target.data;
(*rulenum) = 0;
} else if (s == e) {
(*rulenum)++;
if (s->target_offset == sizeof(struct ipt_entry)
&& strcmp(t->target.u.kernel.target->name,
IPT_STANDARD_TARGET) == 0
&& t->verdict < 0
&& unconditional(&s->ip)) {
/* Tail of chains: STANDARD target (return/policy) */
*comment = *chainname == hookname
? (char *)comments[NF_IP_TRACE_COMMENT_POLICY]
: (char *)comments[NF_IP_TRACE_COMMENT_RETURN];
}
return 1;
} else
(*rulenum)++;
return 0;
}
static void trace_packet(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
char *tablename,
struct xt_table_info *private,
struct ipt_entry *e)
{
void *table_base;
struct ipt_entry *root;
char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
table_base = (void *)private->entries[smp_processor_id()];
root = get_entry(table_base, private->hook_entry[hook]);
hookname = chainname = (char *)hooknames[hook];
comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE];
IPT_ENTRY_ITERATE(root,
private->size - private->hook_entry[hook],
get_chainname_rulenum,
e, hookname, &chainname, &comment, &rulenum);
nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo,
"TRACE: %s:%s:%s:%u ",
tablename, chainname, comment, rulenum);
}
#endif
/* Returns one of the generic firewall policies, like NF_ACCEPT. */ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int unsigned int
ipt_do_table(struct sk_buff **pskb, ipt_do_table(struct sk_buff **pskb,
...@@ -261,6 +367,14 @@ ipt_do_table(struct sk_buff **pskb, ...@@ -261,6 +367,14 @@ ipt_do_table(struct sk_buff **pskb,
t = ipt_get_target(e); t = ipt_get_target(e);
IP_NF_ASSERT(t->u.kernel.target); IP_NF_ASSERT(t->u.kernel.target);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* The packet is traced: log it */
if (unlikely((*pskb)->nf_trace))
trace_packet(*pskb, hook, in, out,
table->name, private, e);
#endif
/* Standard target? */ /* Standard target? */
if (!t->u.kernel.target->target) { if (!t->u.kernel.target->target) {
int v; int v;
...@@ -341,19 +455,6 @@ ipt_do_table(struct sk_buff **pskb, ...@@ -341,19 +455,6 @@ ipt_do_table(struct sk_buff **pskb,
#endif #endif
} }
/* All zeroes == unconditional rule. */
static inline int
unconditional(const struct ipt_ip *ip)
{
unsigned int i;
for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
if (((__u32 *)ip)[i])
return 0;
return 1;
}
/* Figures out from what hook each rule can be called: returns 0 if /* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */ there are loops. Puts hook bitmask in comefrom. */
static int static int
......
...@@ -521,6 +521,10 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) ...@@ -521,6 +521,10 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index; to->tc_index = from->tc_index;
#endif #endif
nf_copy(to, from); nf_copy(to, from);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
to->nf_trace = from->nf_trace;
#endif
skb_copy_secmark(to, from); skb_copy_secmark(to, from);
} }
......
...@@ -241,6 +241,113 @@ get_entry(void *base, unsigned int offset) ...@@ -241,6 +241,113 @@ get_entry(void *base, unsigned int offset)
return (struct ip6t_entry *)(base + offset); return (struct ip6t_entry *)(base + offset);
} }
/* All zeroes == unconditional rule. */
static inline int
unconditional(const struct ip6t_ip6 *ipv6)
{
unsigned int i;
for (i = 0; i < sizeof(*ipv6); i++)
if (((char *)ipv6)[i])
break;
return (i == sizeof(*ipv6));
}
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* This cries for unification! */
static const char *hooknames[] = {
[NF_IP6_PRE_ROUTING] = "PREROUTING",
[NF_IP6_LOCAL_IN] = "INPUT",
[NF_IP6_FORWARD] = "FORWARD",
[NF_IP6_LOCAL_OUT] = "OUTPUT",
[NF_IP6_POST_ROUTING] = "POSTROUTING",
};
enum nf_ip_trace_comments {
NF_IP6_TRACE_COMMENT_RULE,
NF_IP6_TRACE_COMMENT_RETURN,
NF_IP6_TRACE_COMMENT_POLICY,
};
static const char *comments[] = {
[NF_IP6_TRACE_COMMENT_RULE] = "rule",
[NF_IP6_TRACE_COMMENT_RETURN] = "return",
[NF_IP6_TRACE_COMMENT_POLICY] = "policy",
};
static struct nf_loginfo trace_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
.log = {
.level = 4,
.logflags = NF_LOG_MASK,
},
},
};
static inline int
get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
char *hookname, char **chainname,
char **comment, unsigned int *rulenum)
{
struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
*chainname = t->target.data;
(*rulenum) = 0;
} else if (s == e) {
(*rulenum)++;
if (s->target_offset == sizeof(struct ip6t_entry)
&& strcmp(t->target.u.kernel.target->name,
IP6T_STANDARD_TARGET) == 0
&& t->verdict < 0
&& unconditional(&s->ipv6)) {
/* Tail of chains: STANDARD target (return/policy) */
*comment = *chainname == hookname
? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY]
: (char *)comments[NF_IP6_TRACE_COMMENT_RETURN];
}
return 1;
} else
(*rulenum)++;
return 0;
}
static void trace_packet(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
char *tablename,
struct xt_table_info *private,
struct ip6t_entry *e)
{
void *table_base;
struct ip6t_entry *root;
char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
table_base = (void *)private->entries[smp_processor_id()];
root = get_entry(table_base, private->hook_entry[hook]);
hookname = chainname = (char *)hooknames[hook];
comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE];
IP6T_ENTRY_ITERATE(root,
private->size - private->hook_entry[hook],
get_chainname_rulenum,
e, hookname, &chainname, &comment, &rulenum);
nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
"TRACE: %s:%s:%s:%u ",
tablename, chainname, comment, rulenum);
}
#endif
/* Returns one of the generic firewall policies, like NF_ACCEPT. */ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int unsigned int
ip6t_do_table(struct sk_buff **pskb, ip6t_do_table(struct sk_buff **pskb,
...@@ -298,6 +405,14 @@ ip6t_do_table(struct sk_buff **pskb, ...@@ -298,6 +405,14 @@ ip6t_do_table(struct sk_buff **pskb,
t = ip6t_get_target(e); t = ip6t_get_target(e);
IP_NF_ASSERT(t->u.kernel.target); IP_NF_ASSERT(t->u.kernel.target);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* The packet is traced: log it */
if (unlikely((*pskb)->nf_trace))
trace_packet(*pskb, hook, in, out,
table->name, private, e);
#endif
/* Standard target? */ /* Standard target? */
if (!t->u.kernel.target->target) { if (!t->u.kernel.target->target) {
int v; int v;
...@@ -377,19 +492,6 @@ ip6t_do_table(struct sk_buff **pskb, ...@@ -377,19 +492,6 @@ ip6t_do_table(struct sk_buff **pskb,
#endif #endif
} }
/* All zeroes == unconditional rule. */
static inline int
unconditional(const struct ip6t_ip6 *ipv6)
{
unsigned int i;
for (i = 0; i < sizeof(*ipv6); i++)
if (((char *)ipv6)[i])
break;
return (i == sizeof(*ipv6));
}
/* Figures out from what hook each rule can be called: returns 0 if /* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */ there are loops. Puts hook bitmask in comefrom. */
static int static int
......
...@@ -343,6 +343,18 @@ config NETFILTER_XT_TARGET_NOTRACK ...@@ -343,6 +343,18 @@ config NETFILTER_XT_TARGET_NOTRACK
If you want to compile it as a module, say M here and read If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'. <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_TARGET_TRACE
tristate '"TRACE" target support'
depends on NETFILTER_XTABLES
depends on IP_NF_RAW || IP6_NF_RAW
help
The TRACE target allows you to mark packets so that the kernel
will log every rule which match the packets as those traverse
the tables, chains, rules.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_SECMARK
tristate '"SECMARK" target support' tristate '"SECMARK" target support'
depends on NETFILTER_XTABLES && NETWORK_SECMARK depends on NETFILTER_XTABLES && NETWORK_SECMARK
......
...@@ -44,6 +44,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o ...@@ -44,6 +44,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
......
/* This is a module which is used to mark packets for tracing.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_TRACE");
MODULE_ALIAS("ip6t_TRACE");
static unsigned int
target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
(*pskb)->nf_trace = 1;
return XT_CONTINUE;
}
static struct xt_target xt_trace_target[] = {
{
.name = "TRACE",
.family = AF_INET,
.target = target,
.table = "raw",
.me = THIS_MODULE,
},
{
.name = "TRACE",
.family = AF_INET6,
.target = target,
.table = "raw",
.me = THIS_MODULE,
},
};
static int __init xt_trace_init(void)
{
return xt_register_targets(xt_trace_target,
ARRAY_SIZE(xt_trace_target));
}
static void __exit xt_trace_fini(void)
{
xt_unregister_targets(xt_trace_target, ARRAY_SIZE(xt_trace_target));
}
module_init(xt_trace_init);
module_exit(xt_trace_fini);
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