]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/netfilter/xt_conntrack.c
Merge branch 'upstream/wm8350' into for-2.6.32
[mv-sheeva.git] / net / netfilter / xt_conntrack.c
index 0b7139f3dd786b3b4fa9ac416ca20fb9fbfe47c4..6dc4652f2fe8fdb5a9775b71f68e10970f057476 100644 (file)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: connection tracking state match");
 MODULE_ALIAS("ipt_conntrack");
 MODULE_ALIAS("ip6t_conntrack");
 
-static bool
-conntrack_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
-{
-       const struct xt_conntrack_info *sinfo = par->matchinfo;
-       const struct nf_conn *ct;
-       enum ip_conntrack_info ctinfo;
-       unsigned int statebit;
-
-       ct = nf_ct_get(skb, &ctinfo);
-
-#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & (invflg)))
-
-       if (ct == &nf_conntrack_untracked)
-               statebit = XT_CONNTRACK_STATE_UNTRACKED;
-       else if (ct)
-               statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
-       else
-               statebit = XT_CONNTRACK_STATE_INVALID;
-
-       if (sinfo->flags & XT_CONNTRACK_STATE) {
-               if (ct) {
-                       if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
-                               statebit |= XT_CONNTRACK_STATE_SNAT;
-                       if (test_bit(IPS_DST_NAT_BIT, &ct->status))
-                               statebit |= XT_CONNTRACK_STATE_DNAT;
-               }
-               if (FWINV((statebit & sinfo->statemask) == 0,
-                         XT_CONNTRACK_STATE))
-                       return false;
-       }
-
-       if (ct == NULL) {
-               if (sinfo->flags & ~XT_CONNTRACK_STATE)
-                       return false;
-               return true;
-       }
-
-       if (sinfo->flags & XT_CONNTRACK_PROTO &&
-           FWINV(nf_ct_protonum(ct) !=
-                 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
-                 XT_CONNTRACK_PROTO))
-               return false;
-
-       if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
-           FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
-                  sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
-                 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
-                 XT_CONNTRACK_ORIGSRC))
-               return false;
-
-       if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
-           FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
-                  sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
-                 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
-                 XT_CONNTRACK_ORIGDST))
-               return false;
-
-       if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
-           FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
-                  sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
-                 sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
-                 XT_CONNTRACK_REPLSRC))
-               return false;
-
-       if (sinfo->flags & XT_CONNTRACK_REPLDST &&
-           FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
-                  sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
-                 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
-                 XT_CONNTRACK_REPLDST))
-               return false;
-
-       if (sinfo->flags & XT_CONNTRACK_STATUS &&
-           FWINV((ct->status & sinfo->statusmask) == 0,
-                 XT_CONNTRACK_STATUS))
-               return false;
-
-       if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
-               unsigned long expires = timer_pending(&ct->timeout) ?
-                                       (ct->timeout.expires - jiffies)/HZ : 0;
-
-               if (FWINV(!(expires >= sinfo->expires_min &&
-                           expires <= sinfo->expires_max),
-                         XT_CONNTRACK_EXPIRES))
-                       return false;
-       }
-       return true;
-#undef FWINV
-}
-
 static bool
 conntrack_addrcmp(const union nf_inet_addr *kaddr,
                   const union nf_inet_addr *uaddr,
@@ -129,7 +40,7 @@ conntrack_addrcmp(const union nf_inet_addr *kaddr,
 
 static inline bool
 conntrack_mt_origsrc(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
@@ -138,7 +49,7 @@ conntrack_mt_origsrc(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_origdst(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
@@ -147,7 +58,7 @@ conntrack_mt_origdst(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_replsrc(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
@@ -156,7 +67,7 @@ conntrack_mt_replsrc(const struct nf_conn *ct,
 
 static inline bool
 conntrack_mt_repldst(const struct nf_conn *ct,
-                     const struct xt_conntrack_mtinfo1 *info,
+                     const struct xt_conntrack_mtinfo2 *info,
                     u_int8_t family)
 {
        return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
@@ -164,7 +75,7 @@ conntrack_mt_repldst(const struct nf_conn *ct,
 }
 
 static inline bool
-ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
+ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
                     const struct nf_conn *ct)
 {
        const struct nf_conntrack_tuple *tuple;
@@ -204,7 +115,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
 static bool
 conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
-       const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
+       const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
        enum ip_conntrack_info ctinfo;
        const struct nf_conn *ct;
        unsigned int statebit;
@@ -278,6 +189,16 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
+static bool
+conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+       const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo;
+       struct xt_match_param newpar = *par;
+
+       newpar.matchinfo = *info;
+       return conntrack_mt(skb, &newpar);
+}
+
 static bool conntrack_mt_check(const struct xt_mtchk_param *par)
 {
        if (nf_ct_l3proto_try_module_get(par->family) < 0) {
@@ -288,81 +209,61 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par)
        return true;
 }
 
-static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
+static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par)
 {
-       nf_ct_l3proto_module_put(par->family);
-}
+       struct xt_conntrack_mtinfo1 *info = par->matchinfo;
+       struct xt_conntrack_mtinfo2 *up;
+       int ret = conntrack_mt_check(par);
 
-#ifdef CONFIG_COMPAT
-struct compat_xt_conntrack_info
-{
-       compat_uint_t                   statemask;
-       compat_uint_t                   statusmask;
-       struct ip_conntrack_old_tuple   tuple[IP_CT_DIR_MAX];
-       struct in_addr                  sipmsk[IP_CT_DIR_MAX];
-       struct in_addr                  dipmsk[IP_CT_DIR_MAX];
-       compat_ulong_t                  expires_min;
-       compat_ulong_t                  expires_max;
-       u_int8_t                        flags;
-       u_int8_t                        invflags;
-};
+       if (ret < 0)
+               return ret;
+
+       up = kmalloc(sizeof(*up), GFP_KERNEL);
+       if (up == NULL) {
+               nf_ct_l3proto_module_put(par->family);
+               return -ENOMEM;
+       }
 
-static void conntrack_mt_compat_from_user_v0(void *dst, void *src)
+       /*
+        * The strategy here is to minimize the overhead of v1 matching,
+        * by prebuilding a v2 struct and putting the pointer into the
+        * v1 dataspace.
+        */
+       memcpy(up, info, offsetof(typeof(*info), state_mask));
+       up->state_mask  = info->state_mask;
+       up->status_mask = info->status_mask;
+       *(void **)info  = up;
+       return true;
+}
+
+static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
 {
-       const struct compat_xt_conntrack_info *cm = src;
-       struct xt_conntrack_info m = {
-               .statemask      = cm->statemask,
-               .statusmask     = cm->statusmask,
-               .expires_min    = cm->expires_min,
-               .expires_max    = cm->expires_max,
-               .flags          = cm->flags,
-               .invflags       = cm->invflags,
-       };
-       memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
-       memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
-       memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
-       memcpy(dst, &m, sizeof(m));
+       nf_ct_l3proto_module_put(par->family);
 }
 
-static int conntrack_mt_compat_to_user_v0(void __user *dst, void *src)
+static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par)
 {
-       const struct xt_conntrack_info *m = src;
-       struct compat_xt_conntrack_info cm = {
-               .statemask      = m->statemask,
-               .statusmask     = m->statusmask,
-               .expires_min    = m->expires_min,
-               .expires_max    = m->expires_max,
-               .flags          = m->flags,
-               .invflags       = m->invflags,
-       };
-       memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
-       memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
-       memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
-       return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
+       struct xt_conntrack_mtinfo2 **info = par->matchinfo;
+       kfree(*info);
+       conntrack_mt_destroy(par);
 }
-#endif
 
 static struct xt_match conntrack_mt_reg[] __read_mostly = {
        {
                .name       = "conntrack",
-               .revision   = 0,
-               .family     = NFPROTO_IPV4,
-               .match      = conntrack_mt_v0,
-               .checkentry = conntrack_mt_check,
-               .destroy    = conntrack_mt_destroy,
-               .matchsize  = sizeof(struct xt_conntrack_info),
+               .revision   = 1,
+               .family     = NFPROTO_UNSPEC,
+               .matchsize  = sizeof(struct xt_conntrack_mtinfo1),
+               .match      = conntrack_mt_v1,
+               .checkentry = conntrack_mt_check_v1,
+               .destroy    = conntrack_mt_destroy_v1,
                .me         = THIS_MODULE,
-#ifdef CONFIG_COMPAT
-               .compatsize       = sizeof(struct compat_xt_conntrack_info),
-               .compat_from_user = conntrack_mt_compat_from_user_v0,
-               .compat_to_user   = conntrack_mt_compat_to_user_v0,
-#endif
        },
        {
                .name       = "conntrack",
-               .revision   = 1,
+               .revision   = 2,
                .family     = NFPROTO_UNSPEC,
-               .matchsize  = sizeof(struct xt_conntrack_mtinfo1),
+               .matchsize  = sizeof(struct xt_conntrack_mtinfo2),
                .match      = conntrack_mt,
                .checkentry = conntrack_mt_check,
                .destroy    = conntrack_mt_destroy,