summaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2007-07-08 07:21:23 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-11 07:17:14 +0200
commitba9dda3ab5a865542e69dfe01edb2436857c9420 (patch)
tree93f92442a8ad134d78b4d7cd8dc74e089baef3d7 /net/ipv6
parent[NETFILTER]: Add u32 match (diff)
downloadlinux-ba9dda3ab5a865542e69dfe01edb2436857c9420.tar.xz
linux-ba9dda3ab5a865542e69dfe01edb2436857c9420.zip
[NETFILTER]: x_tables: add TRACE target
The TRACE target can be used to follow IP and IPv6 packets through the ruleset. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick NcHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_output.c4
-rw-r--r--net/ipv6/netfilter/ip6_tables.c128
2 files changed, 119 insertions, 13 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 31dafaf0b652..50d86e94d9ed 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -521,6 +521,10 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
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);
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 7fe4d29708cb..4f93b79163aa 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -241,6 +241,113 @@ get_entry(void *base, unsigned int 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. */
unsigned int
ip6t_do_table(struct sk_buff **pskb,
@@ -298,6 +405,14 @@ ip6t_do_table(struct sk_buff **pskb,
t = ip6t_get_target(e);
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? */
if (!t->u.kernel.target->target) {
int v;
@@ -377,19 +492,6 @@ ip6t_do_table(struct sk_buff **pskb,
#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
there are loops. Puts hook bitmask in comefrom. */
static int