diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2007-07-08 01:21:23 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:17:14 -0400 |
commit | ba9dda3ab5a865542e69dfe01edb2436857c9420 (patch) | |
tree | 93f92442a8ad134d78b4d7cd8dc74e089baef3d7 /net/ipv6 | |
parent | 1b50b8a371e90a5e110f466e4ac02cf6b5f681de (diff) |
[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) | |||
521 | to->tc_index = from->tc_index; | 521 | to->tc_index = from->tc_index; |
522 | #endif | 522 | #endif |
523 | nf_copy(to, from); | 523 | nf_copy(to, from); |
524 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | ||
525 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
526 | to->nf_trace = from->nf_trace; | ||
527 | #endif | ||
524 | skb_copy_secmark(to, from); | 528 | skb_copy_secmark(to, from); |
525 | } | 529 | } |
526 | 530 | ||
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) | |||
241 | return (struct ip6t_entry *)(base + offset); | 241 | return (struct ip6t_entry *)(base + offset); |
242 | } | 242 | } |
243 | 243 | ||
244 | /* All zeroes == unconditional rule. */ | ||
245 | static inline int | ||
246 | unconditional(const struct ip6t_ip6 *ipv6) | ||
247 | { | ||
248 | unsigned int i; | ||
249 | |||
250 | for (i = 0; i < sizeof(*ipv6); i++) | ||
251 | if (((char *)ipv6)[i]) | ||
252 | break; | ||
253 | |||
254 | return (i == sizeof(*ipv6)); | ||
255 | } | ||
256 | |||
257 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | ||
258 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
259 | /* This cries for unification! */ | ||
260 | static const char *hooknames[] = { | ||
261 | [NF_IP6_PRE_ROUTING] = "PREROUTING", | ||
262 | [NF_IP6_LOCAL_IN] = "INPUT", | ||
263 | [NF_IP6_FORWARD] = "FORWARD", | ||
264 | [NF_IP6_LOCAL_OUT] = "OUTPUT", | ||
265 | [NF_IP6_POST_ROUTING] = "POSTROUTING", | ||
266 | }; | ||
267 | |||
268 | enum nf_ip_trace_comments { | ||
269 | NF_IP6_TRACE_COMMENT_RULE, | ||
270 | NF_IP6_TRACE_COMMENT_RETURN, | ||
271 | NF_IP6_TRACE_COMMENT_POLICY, | ||
272 | }; | ||
273 | |||
274 | static const char *comments[] = { | ||
275 | [NF_IP6_TRACE_COMMENT_RULE] = "rule", | ||
276 | [NF_IP6_TRACE_COMMENT_RETURN] = "return", | ||
277 | [NF_IP6_TRACE_COMMENT_POLICY] = "policy", | ||
278 | }; | ||
279 | |||
280 | static struct nf_loginfo trace_loginfo = { | ||
281 | .type = NF_LOG_TYPE_LOG, | ||
282 | .u = { | ||
283 | .log = { | ||
284 | .level = 4, | ||
285 | .logflags = NF_LOG_MASK, | ||
286 | }, | ||
287 | }, | ||
288 | }; | ||
289 | |||
290 | static inline int | ||
291 | get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | ||
292 | char *hookname, char **chainname, | ||
293 | char **comment, unsigned int *rulenum) | ||
294 | { | ||
295 | struct ip6t_standard_target *t = (void *)ip6t_get_target(s); | ||
296 | |||
297 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { | ||
298 | /* Head of user chain: ERROR target with chainname */ | ||
299 | *chainname = t->target.data; | ||
300 | (*rulenum) = 0; | ||
301 | } else if (s == e) { | ||
302 | (*rulenum)++; | ||
303 | |||
304 | if (s->target_offset == sizeof(struct ip6t_entry) | ||
305 | && strcmp(t->target.u.kernel.target->name, | ||
306 | IP6T_STANDARD_TARGET) == 0 | ||
307 | && t->verdict < 0 | ||
308 | && unconditional(&s->ipv6)) { | ||
309 | /* Tail of chains: STANDARD target (return/policy) */ | ||
310 | *comment = *chainname == hookname | ||
311 | ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY] | ||
312 | : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN]; | ||
313 | } | ||
314 | return 1; | ||
315 | } else | ||
316 | (*rulenum)++; | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static void trace_packet(struct sk_buff *skb, | ||
322 | unsigned int hook, | ||
323 | const struct net_device *in, | ||
324 | const struct net_device *out, | ||
325 | char *tablename, | ||
326 | struct xt_table_info *private, | ||
327 | struct ip6t_entry *e) | ||
328 | { | ||
329 | void *table_base; | ||
330 | struct ip6t_entry *root; | ||
331 | char *hookname, *chainname, *comment; | ||
332 | unsigned int rulenum = 0; | ||
333 | |||
334 | table_base = (void *)private->entries[smp_processor_id()]; | ||
335 | root = get_entry(table_base, private->hook_entry[hook]); | ||
336 | |||
337 | hookname = chainname = (char *)hooknames[hook]; | ||
338 | comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE]; | ||
339 | |||
340 | IP6T_ENTRY_ITERATE(root, | ||
341 | private->size - private->hook_entry[hook], | ||
342 | get_chainname_rulenum, | ||
343 | e, hookname, &chainname, &comment, &rulenum); | ||
344 | |||
345 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | ||
346 | "TRACE: %s:%s:%s:%u ", | ||
347 | tablename, chainname, comment, rulenum); | ||
348 | } | ||
349 | #endif | ||
350 | |||
244 | /* Returns one of the generic firewall policies, like NF_ACCEPT. */ | 351 | /* Returns one of the generic firewall policies, like NF_ACCEPT. */ |
245 | unsigned int | 352 | unsigned int |
246 | ip6t_do_table(struct sk_buff **pskb, | 353 | ip6t_do_table(struct sk_buff **pskb, |
@@ -298,6 +405,14 @@ ip6t_do_table(struct sk_buff **pskb, | |||
298 | 405 | ||
299 | t = ip6t_get_target(e); | 406 | t = ip6t_get_target(e); |
300 | IP_NF_ASSERT(t->u.kernel.target); | 407 | IP_NF_ASSERT(t->u.kernel.target); |
408 | |||
409 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | ||
410 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
411 | /* The packet is traced: log it */ | ||
412 | if (unlikely((*pskb)->nf_trace)) | ||
413 | trace_packet(*pskb, hook, in, out, | ||
414 | table->name, private, e); | ||
415 | #endif | ||
301 | /* Standard target? */ | 416 | /* Standard target? */ |
302 | if (!t->u.kernel.target->target) { | 417 | if (!t->u.kernel.target->target) { |
303 | int v; | 418 | int v; |
@@ -377,19 +492,6 @@ ip6t_do_table(struct sk_buff **pskb, | |||
377 | #endif | 492 | #endif |
378 | } | 493 | } |
379 | 494 | ||
380 | /* All zeroes == unconditional rule. */ | ||
381 | static inline int | ||
382 | unconditional(const struct ip6t_ip6 *ipv6) | ||
383 | { | ||
384 | unsigned int i; | ||
385 | |||
386 | for (i = 0; i < sizeof(*ipv6); i++) | ||
387 | if (((char *)ipv6)[i]) | ||
388 | break; | ||
389 | |||
390 | return (i == sizeof(*ipv6)); | ||
391 | } | ||
392 | |||
393 | /* Figures out from what hook each rule can be called: returns 0 if | 495 | /* Figures out from what hook each rule can be called: returns 0 if |
394 | there are loops. Puts hook bitmask in comefrom. */ | 496 | there are loops. Puts hook bitmask in comefrom. */ |
395 | static int | 497 | static int |