]> err.no Git - linux-2.6/blobdiff - net/ipv4/netfilter/ip_tables.c
Pull bugzilla-7880 into release branch
[linux-2.6] / net / ipv4 / netfilter / ip_tables.c
index e2a8938256564fb5e3956fd2601bed247a06a283..e1b402c6b855a50072d127974e9002c518fa3872 100644 (file)
@@ -152,20 +152,20 @@ ip_packet_match(const struct iphdr *ip,
        return 1;
 }
 
-static inline int
+static inline bool
 ip_checkentry(const struct ipt_ip *ip)
 {
        if (ip->flags & ~IPT_F_MASK) {
                duprintf("Unknown flag bits set: %08X\n",
                         ip->flags & ~IPT_F_MASK);
-               return 0;
+               return false;
        }
        if (ip->invflags & ~IPT_INV_MASK) {
                duprintf("Unknown invflag bits set: %08X\n",
                         ip->invflags & ~IPT_INV_MASK);
-               return 0;
+               return false;
        }
-       return 1;
+       return true;
 }
 
 static unsigned int
@@ -183,19 +183,19 @@ ipt_error(struct sk_buff **pskb,
 }
 
 static inline
-int do_match(struct ipt_entry_match *m,
-            const struct sk_buff *skb,
-            const struct net_device *in,
-            const struct net_device *out,
-            int offset,
-            bool *hotdrop)
+bool do_match(struct ipt_entry_match *m,
+             const struct sk_buff *skb,
+             const struct net_device *in,
+             const struct net_device *out,
+             int offset,
+             bool *hotdrop)
 {
        /* Stop iteration if it doesn't match */
        if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
                                      offset, ip_hdrlen(skb), hotdrop))
-               return 1;
+               return true;
        else
-               return 0;
+               return false;
 }
 
 static inline struct ipt_entry *
@@ -204,6 +204,112 @@ get_entry(void *base, unsigned int offset)
        return (struct ipt_entry *)(base + offset);
 }
 
+/* All zeroes == unconditional rule. */
+static inline int
+unconditional(const struct ipt_ip *ip)
+{
+       unsigned int i;
+
+       for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
+               if (((__u32 *)ip)[i])
+                       return 0;
+
+       return 1;
+}
+
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+static const char *hooknames[] = {
+       [NF_IP_PRE_ROUTING]             = "PREROUTING",
+       [NF_IP_LOCAL_IN]                = "INPUT",
+       [NF_IP_FORWARD]                 = "FORWARD",
+       [NF_IP_LOCAL_OUT]               = "OUTPUT",
+       [NF_IP_POST_ROUTING]            = "POSTROUTING",
+};
+
+enum nf_ip_trace_comments {
+       NF_IP_TRACE_COMMENT_RULE,
+       NF_IP_TRACE_COMMENT_RETURN,
+       NF_IP_TRACE_COMMENT_POLICY,
+};
+
+static const char *comments[] = {
+       [NF_IP_TRACE_COMMENT_RULE]      = "rule",
+       [NF_IP_TRACE_COMMENT_RETURN]    = "return",
+       [NF_IP_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 ipt_entry *s, struct ipt_entry *e,
+                     char *hookname, char **chainname,
+                     char **comment, unsigned int *rulenum)
+{
+       struct ipt_standard_target *t = (void *)ipt_get_target(s);
+
+       if (strcmp(t->target.u.kernel.target->name, IPT_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 ipt_entry)
+                  && strcmp(t->target.u.kernel.target->name,
+                            IPT_STANDARD_TARGET) == 0
+                  && t->verdict < 0
+                  && unconditional(&s->ip)) {
+                       /* Tail of chains: STANDARD target (return/policy) */
+                       *comment = *chainname == hookname
+                               ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY]
+                               : (char *)comments[NF_IP_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 ipt_entry *e)
+{
+       void *table_base;
+       struct ipt_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_IP_TRACE_COMMENT_RULE];
+
+       IPT_ENTRY_ITERATE(root,
+                         private->size - private->hook_entry[hook],
+                         get_chainname_rulenum,
+                         e, hookname, &chainname, &comment, &rulenum);
+
+       nf_log_packet(AF_INET, 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
 ipt_do_table(struct sk_buff **pskb,
@@ -261,6 +367,14 @@ ipt_do_table(struct sk_buff **pskb,
 
                        t = ipt_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;
@@ -341,19 +455,6 @@ ipt_do_table(struct sk_buff **pskb,
 #endif
 }
 
-/* All zeroes == unconditional rule. */
-static inline int
-unconditional(const struct ipt_ip *ip)
-{
-       unsigned int i;
-
-       for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
-               if (((__u32 *)ip)[i])
-                       return 0;
-
-       return 1;
-}
-
 /* Figures out from what hook each rule can be called: returns 0 if
    there are loops.  Puts hook bitmask in comefrom. */
 static int
@@ -2105,16 +2206,16 @@ void ipt_unregister_table(struct xt_table *table)
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
-static inline int
+static inline bool
 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
                     u_int8_t type, u_int8_t code,
-                    int invert)
+                    bool invert)
 {
        return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
                ^ invert;
 }
 
-static int
+static bool
 icmp_match(const struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out,
@@ -2129,7 +2230,7 @@ icmp_match(const struct sk_buff *skb,
 
        /* Must not be a fragment. */
        if (offset)
-               return 0;
+               return false;
 
        ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
        if (ic == NULL) {
@@ -2138,7 +2239,7 @@ icmp_match(const struct sk_buff *skb,
                 */
                duprintf("Dropping evil ICMP tinygram.\n");
                *hotdrop = true;
-               return 0;
+               return false;
        }
 
        return icmp_type_code_match(icmpinfo->type,
@@ -2149,7 +2250,7 @@ icmp_match(const struct sk_buff *skb,
 }
 
 /* Called when user tries to insert an entry of this type. */
-static int
+static bool
 icmp_checkentry(const char *tablename,
           const void *info,
           const struct xt_match *match,
@@ -2163,7 +2264,7 @@ icmp_checkentry(const char *tablename,
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct xt_target ipt_standard_target = {
+static struct xt_target ipt_standard_target __read_mostly = {
        .name           = IPT_STANDARD_TARGET,
        .targetsize     = sizeof(int),
        .family         = AF_INET,
@@ -2174,7 +2275,7 @@ static struct xt_target ipt_standard_target = {
 #endif
 };
 
-static struct xt_target ipt_error_target = {
+static struct xt_target ipt_error_target __read_mostly = {
        .name           = IPT_ERROR_TARGET,
        .target         = ipt_error,
        .targetsize     = IPT_FUNCTION_MAXNAMELEN,
@@ -2197,7 +2298,7 @@ static struct nf_sockopt_ops ipt_sockopts = {
 #endif
 };
 
-static struct xt_match icmp_matchstruct = {
+static struct xt_match icmp_matchstruct __read_mostly = {
        .name           = "icmp",
        .match          = icmp_match,
        .matchsize      = sizeof(struct ipt_icmp),
@@ -2230,7 +2331,7 @@ static int __init ip_tables_init(void)
        if (ret < 0)
                goto err5;
 
-       printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
+       printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
        return 0;
 
 err5: