netfilter: xt_qtaguid: fix ipv6 protocol lookup
JP Abgrall [Tue, 17 Apr 2012 23:00:07 +0000 (16:00 -0700)]
When updating the stats for a given uid it would incorrectly assume
IPV4 and pick up the wrong protocol when IPV6.

Change-Id: Iea4a635012b4123bf7aa93809011b7b2040bb3d5
Signed-off-by: JP Abgrall <jpa@google.com>

net/netfilter/xt_qtaguid.c

index 3d39282..2c1170f 100644 (file)
 #include <net/tcp.h>
 #include <net/udp.h>
 
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#endif
+
 #include <linux/netfilter/xt_socket.h>
 #include "xt_qtaguid_internal.h"
 #include "xt_qtaguid_print.h"
@@ -1546,6 +1550,27 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
        return sk;
 }
 
+static int ipx_proto(const struct sk_buff *skb,
+                    struct xt_action_param *par)
+{
+       int thoff = 0, tproto;
+
+       switch (par->family) {
+       case NFPROTO_IPV6:
+               tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
+               if (tproto < 0)
+                       MT_DEBUG("%s(): transport header not found in ipv6"
+                                " skb=%p\n", __func__, skb);
+               break;
+       case NFPROTO_IPV4:
+               tproto = ip_hdr(skb)->protocol;
+               break;
+       default:
+               tproto = IPPROTO_RAW;
+       }
+       return tproto;
+}
+
 static void account_for_uid(const struct sk_buff *skb,
                            const struct sock *alternate_sk, uid_t uid,
                            struct xt_action_param *par)
@@ -1572,15 +1597,15 @@ static void account_for_uid(const struct sk_buff *skb,
        } else if (unlikely(!el_dev->name)) {
                pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum);
        } else {
-               MT_DEBUG("qtaguid[%d]: dev name=%s type=%d\n",
-                        par->hooknum,
-                        el_dev->name,
-                        el_dev->type);
+               int proto = ipx_proto(skb, par);
+               MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
+                        par->hooknum, el_dev->name, el_dev->type,
+                        par->family, proto);
 
                if_tag_stat_update(el_dev->name, uid,
                                skb->sk ? skb->sk : alternate_sk,
                                par->in ? IFS_RX : IFS_TX,
-                               ip_hdr(skb)->protocol, skb->len);
+                               proto, skb->len);
        }
 }
 
@@ -1625,8 +1650,8 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
        } else {
                atomic64_inc(&qtu_events.match_found_sk);
        }
-       MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d proto=%d\n",
-               par->hooknum, sk, got_sock, ip_hdr(skb)->protocol);
+       MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
+                par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
        if (sk != NULL) {
                MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
                        par->hooknum, sk, sk->sk_socket,