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/ipv4 | |
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/ipv4')
-rw-r--r-- | net/ipv4/ip_output.c | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 127 |
2 files changed, 118 insertions, 13 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a7dd343d3a03..c9e2b5e6305e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -399,6 +399,10 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
399 | to->tc_index = from->tc_index; | 399 | to->tc_index = from->tc_index; |
400 | #endif | 400 | #endif |
401 | nf_copy(to, from); | 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 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) | 406 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) |
403 | to->ipvs_property = from->ipvs_property; | 407 | to->ipvs_property = from->ipvs_property; |
404 | #endif | 408 | #endif |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 7962306df585..650ab52e9157 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -204,6 +204,112 @@ get_entry(void *base, unsigned int offset) | |||
204 | return (struct ipt_entry *)(base + offset); | 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 | /* Returns one of the generic firewall policies, like NF_ACCEPT. */ | 313 | /* Returns one of the generic firewall policies, like NF_ACCEPT. */ |
208 | unsigned int | 314 | unsigned int |
209 | ipt_do_table(struct sk_buff **pskb, | 315 | ipt_do_table(struct sk_buff **pskb, |
@@ -261,6 +367,14 @@ ipt_do_table(struct sk_buff **pskb, | |||
261 | 367 | ||
262 | t = ipt_get_target(e); | 368 | t = ipt_get_target(e); |
263 | IP_NF_ASSERT(t->u.kernel.target); | 369 | IP_NF_ASSERT(t->u.kernel.target); |
370 | |||
371 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | ||
372 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
373 | /* The packet is traced: log it */ | ||
374 | if (unlikely((*pskb)->nf_trace)) | ||
375 | trace_packet(*pskb, hook, in, out, | ||
376 | table->name, private, e); | ||
377 | #endif | ||
264 | /* Standard target? */ | 378 | /* Standard target? */ |
265 | if (!t->u.kernel.target->target) { | 379 | if (!t->u.kernel.target->target) { |
266 | int v; | 380 | int v; |
@@ -341,19 +455,6 @@ ipt_do_table(struct sk_buff **pskb, | |||
341 | #endif | 455 | #endif |
342 | } | 456 | } |
343 | 457 | ||
344 | /* All zeroes == unconditional rule. */ | ||
345 | static inline int | ||
346 | unconditional(const struct ipt_ip *ip) | ||
347 | { | ||
348 | unsigned int i; | ||
349 | |||
350 | for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) | ||
351 | if (((__u32 *)ip)[i]) | ||
352 | return 0; | ||
353 | |||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | /* Figures out from what hook each rule can be called: returns 0 if | 458 | /* Figures out from what hook each rule can be called: returns 0 if |
358 | there are loops. Puts hook bitmask in comefrom. */ | 459 | there are loops. Puts hook bitmask in comefrom. */ |
359 | static int | 460 | static int |