Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Jozsef Kadlecsik and committed by
David S. Miller
ba9dda3a 1b50b8a3

+314 -27
+3 -1
include/linux/skbuff.h
··· 227 227 * @mark: Generic packet mark 228 228 * @nfct: Associated connection, if any 229 229 * @ipvs_property: skbuff is owned by ipvs 230 + * @nf_trace: netfilter packet trace flag 230 231 * @nfctinfo: Relationship of this skb to the connection 231 232 * @nfct_reasm: netfilter conntrack re-assembly pointer 232 233 * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c ··· 279 278 nfctinfo:3; 280 279 __u8 pkt_type:3, 281 280 fclone:2, 282 - ipvs_property:1; 281 + ipvs_property:1, 282 + nf_trace:1; 283 283 __be16 protocol; 284 284 285 285 void (*destructor)(struct sk_buff *skb);
+8
net/core/skbuff.c
··· 428 428 n->destructor = NULL; 429 429 C(mark); 430 430 __nf_copy(n, skb); 431 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 432 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 433 + C(nf_trace); 434 + #endif 431 435 #ifdef CONFIG_NET_SCHED 432 436 C(tc_index); 433 437 #ifdef CONFIG_NET_CLS_ACT ··· 489 485 new->destructor = NULL; 490 486 new->mark = old->mark; 491 487 __nf_copy(new, old); 488 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 489 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 490 + new->nf_trace = old->nf_trace; 491 + #endif 492 492 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) 493 493 new->ipvs_property = old->ipvs_property; 494 494 #endif
+4
net/ipv4/ip_output.c
··· 399 399 to->tc_index = from->tc_index; 400 400 #endif 401 401 nf_copy(to, from); 402 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 403 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 404 + to->nf_trace = from->nf_trace; 405 + #endif 402 406 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) 403 407 to->ipvs_property = from->ipvs_property; 404 408 #endif
+114 -13
net/ipv4/netfilter/ip_tables.c
··· 204 204 return (struct ipt_entry *)(base + offset); 205 205 } 206 206 207 + /* All zeroes == unconditional rule. */ 208 + static inline int 209 + unconditional(const struct ipt_ip *ip) 210 + { 211 + unsigned int i; 212 + 213 + for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) 214 + if (((__u32 *)ip)[i]) 215 + return 0; 216 + 217 + return 1; 218 + } 219 + 220 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 221 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 222 + static const char *hooknames[] = { 223 + [NF_IP_PRE_ROUTING] = "PREROUTING", 224 + [NF_IP_LOCAL_IN] = "INPUT", 225 + [NF_IP_FORWARD] = "FORWARD", 226 + [NF_IP_LOCAL_OUT] = "OUTPUT", 227 + [NF_IP_POST_ROUTING] = "POSTROUTING", 228 + }; 229 + 230 + enum nf_ip_trace_comments { 231 + NF_IP_TRACE_COMMENT_RULE, 232 + NF_IP_TRACE_COMMENT_RETURN, 233 + NF_IP_TRACE_COMMENT_POLICY, 234 + }; 235 + 236 + static const char *comments[] = { 237 + [NF_IP_TRACE_COMMENT_RULE] = "rule", 238 + [NF_IP_TRACE_COMMENT_RETURN] = "return", 239 + [NF_IP_TRACE_COMMENT_POLICY] = "policy", 240 + }; 241 + 242 + static struct nf_loginfo trace_loginfo = { 243 + .type = NF_LOG_TYPE_LOG, 244 + .u = { 245 + .log = { 246 + .level = 4, 247 + .logflags = NF_LOG_MASK, 248 + }, 249 + }, 250 + }; 251 + 252 + static inline int 253 + get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, 254 + char *hookname, char **chainname, 255 + char **comment, unsigned int *rulenum) 256 + { 257 + struct ipt_standard_target *t = (void *)ipt_get_target(s); 258 + 259 + if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) { 260 + /* Head of user chain: ERROR target with chainname */ 261 + *chainname = t->target.data; 262 + (*rulenum) = 0; 263 + } else if (s == e) { 264 + (*rulenum)++; 265 + 266 + if (s->target_offset == sizeof(struct ipt_entry) 267 + && strcmp(t->target.u.kernel.target->name, 268 + IPT_STANDARD_TARGET) == 0 269 + && t->verdict < 0 270 + && unconditional(&s->ip)) { 271 + /* Tail of chains: STANDARD target (return/policy) */ 272 + *comment = *chainname == hookname 273 + ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY] 274 + : (char *)comments[NF_IP_TRACE_COMMENT_RETURN]; 275 + } 276 + return 1; 277 + } else 278 + (*rulenum)++; 279 + 280 + return 0; 281 + } 282 + 283 + static void trace_packet(struct sk_buff *skb, 284 + unsigned int hook, 285 + const struct net_device *in, 286 + const struct net_device *out, 287 + char *tablename, 288 + struct xt_table_info *private, 289 + struct ipt_entry *e) 290 + { 291 + void *table_base; 292 + struct ipt_entry *root; 293 + char *hookname, *chainname, *comment; 294 + unsigned int rulenum = 0; 295 + 296 + table_base = (void *)private->entries[smp_processor_id()]; 297 + root = get_entry(table_base, private->hook_entry[hook]); 298 + 299 + hookname = chainname = (char *)hooknames[hook]; 300 + comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE]; 301 + 302 + IPT_ENTRY_ITERATE(root, 303 + private->size - private->hook_entry[hook], 304 + get_chainname_rulenum, 305 + e, hookname, &chainname, &comment, &rulenum); 306 + 307 + nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, 308 + "TRACE: %s:%s:%s:%u ", 309 + tablename, chainname, comment, rulenum); 310 + } 311 + #endif 312 + 207 313 /* Returns one of the generic firewall policies, like NF_ACCEPT. */ 208 314 unsigned int 209 315 ipt_do_table(struct sk_buff **pskb, ··· 367 261 368 262 t = ipt_get_target(e); 369 263 IP_NF_ASSERT(t->u.kernel.target); 264 + 265 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 266 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 267 + /* The packet is traced: log it */ 268 + if (unlikely((*pskb)->nf_trace)) 269 + trace_packet(*pskb, hook, in, out, 270 + table->name, private, e); 271 + #endif 370 272 /* Standard target? */ 371 273 if (!t->u.kernel.target->target) { 372 274 int v; ··· 453 339 return NF_DROP; 454 340 else return verdict; 455 341 #endif 456 - } 457 - 458 - /* All zeroes == unconditional rule. */ 459 - static inline int 460 - unconditional(const struct ipt_ip *ip) 461 - { 462 - unsigned int i; 463 - 464 - for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) 465 - if (((__u32 *)ip)[i]) 466 - return 0; 467 - 468 - return 1; 469 342 } 470 343 471 344 /* Figures out from what hook each rule can be called: returns 0 if
+4
net/ipv6/ip6_output.c
··· 521 521 to->tc_index = from->tc_index; 522 522 #endif 523 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 528 skb_copy_secmark(to, from); 525 529 } 526 530
+115 -13
net/ipv6/netfilter/ip6_tables.c
··· 241 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 351 /* Returns one of the generic firewall policies, like NF_ACCEPT. */ 245 352 unsigned int 246 353 ip6t_do_table(struct sk_buff **pskb, ··· 405 298 406 299 t = ip6t_get_target(e); 407 300 IP_NF_ASSERT(t->u.kernel.target); 301 + 302 + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ 303 + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) 304 + /* The packet is traced: log it */ 305 + if (unlikely((*pskb)->nf_trace)) 306 + trace_packet(*pskb, hook, in, out, 307 + table->name, private, e); 308 + #endif 408 309 /* Standard target? */ 409 310 if (!t->u.kernel.target->target) { 410 311 int v; ··· 490 375 return NF_DROP; 491 376 else return verdict; 492 377 #endif 493 - } 494 - 495 - /* All zeroes == unconditional rule. */ 496 - static inline int 497 - unconditional(const struct ip6t_ip6 *ipv6) 498 - { 499 - unsigned int i; 500 - 501 - for (i = 0; i < sizeof(*ipv6); i++) 502 - if (((char *)ipv6)[i]) 503 - break; 504 - 505 - return (i == sizeof(*ipv6)); 506 378 } 507 379 508 380 /* Figures out from what hook each rule can be called: returns 0 if
+12
net/netfilter/Kconfig
··· 343 343 If you want to compile it as a module, say M here and read 344 344 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. 345 345 346 + config NETFILTER_XT_TARGET_TRACE 347 + tristate '"TRACE" target support' 348 + depends on NETFILTER_XTABLES 349 + depends on IP_NF_RAW || IP6_NF_RAW 350 + help 351 + The TRACE target allows you to mark packets so that the kernel 352 + will log every rule which match the packets as those traverse 353 + the tables, chains, rules. 354 + 355 + If you want to compile it as a module, say M here and read 356 + <file:Documentation/modules.txt>. If unsure, say `N'. 357 + 346 358 config NETFILTER_XT_TARGET_SECMARK 347 359 tristate '"SECMARK" target support' 348 360 depends on NETFILTER_XTABLES && NETWORK_SECMARK
+1
net/netfilter/Makefile
··· 44 44 obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o 45 45 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o 46 46 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o 47 + obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o 47 48 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o 48 49 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o 49 50 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
+53
net/netfilter/xt_TRACE.c
··· 1 + /* This is a module which is used to mark packets for tracing. 2 + */ 3 + #include <linux/module.h> 4 + #include <linux/skbuff.h> 5 + 6 + #include <linux/netfilter/x_tables.h> 7 + 8 + MODULE_LICENSE("GPL"); 9 + MODULE_ALIAS("ipt_TRACE"); 10 + MODULE_ALIAS("ip6t_TRACE"); 11 + 12 + static unsigned int 13 + target(struct sk_buff **pskb, 14 + const struct net_device *in, 15 + const struct net_device *out, 16 + unsigned int hooknum, 17 + const struct xt_target *target, 18 + const void *targinfo) 19 + { 20 + (*pskb)->nf_trace = 1; 21 + return XT_CONTINUE; 22 + } 23 + 24 + static struct xt_target xt_trace_target[] = { 25 + { 26 + .name = "TRACE", 27 + .family = AF_INET, 28 + .target = target, 29 + .table = "raw", 30 + .me = THIS_MODULE, 31 + }, 32 + { 33 + .name = "TRACE", 34 + .family = AF_INET6, 35 + .target = target, 36 + .table = "raw", 37 + .me = THIS_MODULE, 38 + }, 39 + }; 40 + 41 + static int __init xt_trace_init(void) 42 + { 43 + return xt_register_targets(xt_trace_target, 44 + ARRAY_SIZE(xt_trace_target)); 45 + } 46 + 47 + static void __exit xt_trace_fini(void) 48 + { 49 + xt_unregister_targets(xt_trace_target, ARRAY_SIZE(xt_trace_target)); 50 + } 51 + 52 + module_init(xt_trace_init); 53 + module_exit(xt_trace_fini);