]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/netfilter/xt_conntrack.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
[linux-2.6-omap-h63xx.git] / net / netfilter / xt_conntrack.c
index e92190eafcc5b2cc74ed1a748a73bc7676990472..0c50b289405537348d4004108e7559169ff9031e 100644 (file)
@@ -4,7 +4,6 @@
  *
  *     (C) 2001  Marc Boucher (marc@mbsi.ca).
  *     Copyright © CC Computer Consultants GmbH, 2007 - 2008
- *     Jan Engelhardt <jengelh@computergmbh.de>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2 as
@@ -20,6 +19,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
 MODULE_DESCRIPTION("Xtables: connection tracking state match");
 MODULE_ALIAS("ipt_conntrack");
 MODULE_ALIAS("ip6t_conntrack");
@@ -122,7 +122,7 @@ conntrack_addrcmp(const union nf_inet_addr *kaddr,
                   const union nf_inet_addr *umask, unsigned int l3proto)
 {
        if (l3proto == AF_INET)
-               return (kaddr->ip & umask->ip) == uaddr->ip;
+               return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
        else if (l3proto == AF_INET6)
                return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
                       &uaddr->in6) == 0;
@@ -166,6 +166,44 @@ conntrack_mt_repldst(const struct nf_conn *ct,
               &info->repldst_addr, &info->repldst_mask, family);
 }
 
+static inline bool
+ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
+                    const struct nf_conn *ct)
+{
+       const struct nf_conntrack_tuple *tuple;
+
+       tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+       if ((info->match_flags & XT_CONNTRACK_PROTO) &&
+           (tuple->dst.protonum == info->l4proto) ^
+           !(info->invert_flags & XT_CONNTRACK_PROTO))
+               return false;
+
+       /* Shortcut to match all recognized protocols by using ->src.all. */
+       if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
+           (tuple->src.u.all == info->origsrc_port) ^
+           !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
+               return false;
+
+       if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
+           (tuple->dst.u.all == info->origdst_port) ^
+           !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
+               return false;
+
+       tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+
+       if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
+           (tuple->src.u.all == info->replsrc_port) ^
+           !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
+               return false;
+
+       if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
+           (tuple->dst.u.all == info->repldst_port) ^
+           !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
+               return false;
+
+       return true;
+}
+
 static bool
 conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
              const struct net_device *out, const struct xt_match *match,
@@ -193,17 +231,16 @@ conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
                        if (test_bit(IPS_DST_NAT_BIT, &ct->status))
                                statebit |= XT_CONNTRACK_STATE_DNAT;
                }
-               if ((info->state_mask & statebit) ^
+               if (!!(info->state_mask & statebit) ^
                    !(info->invert_flags & XT_CONNTRACK_STATE))
                        return false;
        }
 
        if (ct == NULL)
                return info->match_flags & XT_CONNTRACK_STATE;
-
-       if ((info->match_flags & XT_CONNTRACK_PROTO) &&
-           ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
-           info->l4proto) ^ !(info->invert_flags & XT_CONNTRACK_PROTO)))
+       if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
+           (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
+           !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
                return false;
 
        if (info->match_flags & XT_CONNTRACK_ORIGSRC)
@@ -226,6 +263,9 @@ conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
                    !(info->invert_flags & XT_CONNTRACK_REPLDST))
                        return false;
 
+       if (!ct_proto_port_check(info, ct))
+               return false;
+
        if ((info->match_flags & XT_CONNTRACK_STATUS) &&
            (!!(info->status_mask & ct->status) ^
            !(info->invert_flags & XT_CONNTRACK_STATUS)))