diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2007-07-07 22:21:23 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-10 22:17:14 -0700 |
commit | ba9dda3ab5a865542e69dfe01edb2436857c9420 (patch) | |
tree | 93f92442a8ad134d78b4d7cd8dc74e089baef3d7 /net/ipv6 | |
parent | 1b50b8a371e90a5e110f466e4ac02cf6b5f681de (diff) | |
download | lwn-ba9dda3ab5a865542e69dfe01edb2436857c9420.tar.gz lwn-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.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 128 |
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 |