[NETFILTER]: Introduce NF_INET_ hook values
[safe/jmp/linux-2.6] / net / ipv6 / netfilter / ip6_tables.c
index 7fe4d29..e1e87ef 100644 (file)
@@ -205,7 +205,7 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
 }
 
 static unsigned int
-ip6t_error(struct sk_buff **pskb,
+ip6t_error(struct sk_buff *skb,
          const struct net_device *in,
          const struct net_device *out,
          unsigned int hooknum,
@@ -241,9 +241,116 @@ 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_INET_PRE_ROUTING]           = "PREROUTING",
+       [NF_INET_LOCAL_IN]              = "INPUT",
+       [NF_INET_FORWARD]               = "FORWARD",
+       [NF_INET_LOCAL_OUT]             = "OUTPUT",
+       [NF_INET_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,
+ip6t_do_table(struct sk_buff *skb,
              unsigned int hook,
              const struct net_device *in,
              const struct net_device *out,
@@ -282,22 +389,30 @@ ip6t_do_table(struct sk_buff **pskb,
        do {
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
-               if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+               if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
                        &protoff, &offset, &hotdrop)) {
                        struct ip6t_entry_target *t;
 
                        if (IP6T_MATCH_ITERATE(e, do_match,
-                                              *pskb, in, out,
+                                              skb, in, out,
                                               offset, protoff, &hotdrop) != 0)
                                goto no_match;
 
                        ADD_COUNTER(e->counters,
-                                   ntohs(ipv6_hdr(*pskb)->payload_len)
+                                   ntohs(ipv6_hdr(skb)->payload_len)
                                    + IPV6_HDR_LEN,
                                    1);
 
                        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(skb->nf_trace))
+                               trace_packet(skb, hook, in, out,
+                                            table->name, private, e);
+#endif
                        /* Standard target? */
                        if (!t->u.kernel.target->target) {
                                int v;
@@ -333,7 +448,7 @@ ip6t_do_table(struct sk_buff **pskb,
                                ((struct ip6t_entry *)table_base)->comefrom
                                        = 0xeeeeeeec;
 #endif
-                               verdict = t->u.kernel.target->target(pskb,
+                               verdict = t->u.kernel.target->target(skb,
                                                                     in, out,
                                                                     hook,
                                                                     t->u.kernel.target,
@@ -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
@@ -400,7 +502,7 @@ mark_source_chains(struct xt_table_info *newinfo,
 
        /* No recursion; use packet counter to save back ptrs (reset
           to 0 as we leave), and comefrom to save source hook bitmask */
-       for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
+       for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
                unsigned int pos = newinfo->hook_entry[hook];
                struct ip6t_entry *e
                        = (struct ip6t_entry *)(entry0 + pos);
@@ -416,13 +518,13 @@ mark_source_chains(struct xt_table_info *newinfo,
                        struct ip6t_standard_target *t
                                = (void *)ip6t_get_target(e);
 
-                       if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
+                       if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
                                printk("iptables: loop hook %u pos %u %08X.\n",
                                       hook, pos, e->comefrom);
                                return 0;
                        }
                        e->comefrom
-                               |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
+                               |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
 
                        /* Unconditional return/END. */
                        if ((e->target_offset == sizeof(struct ip6t_entry)
@@ -442,10 +544,10 @@ mark_source_chains(struct xt_table_info *newinfo,
                                /* Return: backtrack through the last
                                   big jump. */
                                do {
-                                       e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
+                                       e->comefrom ^= (1<<NF_INET_NUMHOOKS);
 #ifdef DEBUG_IP_FIREWALL_USER
                                        if (e->comefrom
-                                           & (1 << NF_IP6_NUMHOOKS)) {
+                                           & (1 << NF_INET_NUMHOOKS)) {
                                                duprintf("Back unset "
                                                         "on hook %u "
                                                         "rule %u\n",
@@ -644,7 +746,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
        }
 
        /* Check hooks & underflows */
-       for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
+       for (h = 0; h < NF_INET_NUMHOOKS; h++) {
                if ((unsigned char *)e - base == hook_entries[h])
                        newinfo->hook_entry[h] = hook_entries[h];
                if ((unsigned char *)e - base == underflows[h])
@@ -698,7 +800,7 @@ translate_table(const char *name,
        newinfo->number = number;
 
        /* Init all hooks to impossible value. */
-       for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
+       for (i = 0; i < NF_INET_NUMHOOKS; i++) {
                newinfo->hook_entry[i] = 0xFFFFFFFF;
                newinfo->underflow[i] = 0xFFFFFFFF;
        }
@@ -722,7 +824,7 @@ translate_table(const char *name,
        }
 
        /* Check hooks all assigned */
-       for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
+       for (i = 0; i < NF_INET_NUMHOOKS; i++) {
                /* Only hooks which are valid */
                if (!(valid_hooks & (1 << i)))
                        continue;
@@ -1339,13 +1441,13 @@ icmp6_checkentry(const char *tablename,
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct xt_target ip6t_standard_target = {
+static struct xt_target ip6t_standard_target __read_mostly = {
        .name           = IP6T_STANDARD_TARGET,
        .targetsize     = sizeof(int),
        .family         = AF_INET6,
 };
 
-static struct xt_target ip6t_error_target = {
+static struct xt_target ip6t_error_target __read_mostly = {
        .name           = IP6T_ERROR_TARGET,
        .target         = ip6t_error,
        .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
@@ -1360,9 +1462,10 @@ static struct nf_sockopt_ops ip6t_sockopts = {
        .get_optmin     = IP6T_BASE_CTL,
        .get_optmax     = IP6T_SO_GET_MAX+1,
        .get            = do_ip6t_get_ctl,
+       .owner          = THIS_MODULE,
 };
 
-static struct xt_match icmp6_matchstruct = {
+static struct xt_match icmp6_matchstruct __read_mostly = {
        .name           = "icmp6",
        .match          = &icmp6_match,
        .matchsize      = sizeof(struct ip6t_icmp),
@@ -1395,7 +1498,7 @@ static int __init ip6_tables_init(void)
        if (ret < 0)
                goto err5;
 
-       printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
+       printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
        return 0;
 
 err5: