]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/netfilter/nf_nat_core.c
netfilter: nf_conntrack: add support for "conntrack zones"
[net-next-2.6.git] / net / ipv4 / netfilter / nf_nat_core.c
index 26066a2327ad3dadba650ff0a8524a9069441f24..4595281c28635b30d4522d75aafdc57e82828b4a 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_zones.h>
 
 static DEFINE_SPINLOCK(nf_nat_lock);
 
@@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put);
 
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
-hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple)
+hash_by_src(const struct net *net, u16 zone,
+           const struct nf_conntrack_tuple *tuple)
 {
        unsigned int hash;
 
        /* Original src, to ensure we map it consistently if poss. */
        hash = jhash_3words((__force u32)tuple->src.u3.ip,
-                           (__force u32)tuple->src.u.all,
+                           (__force u32)tuple->src.u.all ^ zone,
                            tuple->dst.protonum, 0);
        return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
 }
@@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct,
 
 /* Only called for SRC manip */
 static int
-find_appropriate_src(struct net *net,
+find_appropriate_src(struct net *net, u16 zone,
                     const struct nf_conntrack_tuple *tuple,
                     struct nf_conntrack_tuple *result,
                     const struct nf_nat_range *range)
 {
-       unsigned int h = hash_by_src(net, tuple);
+       unsigned int h = hash_by_src(net, zone, tuple);
        const struct nf_conn_nat *nat;
        const struct nf_conn *ct;
        const struct hlist_node *n;
@@ -152,7 +154,7 @@ find_appropriate_src(struct net *net,
        rcu_read_lock();
        hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
                ct = nat->ct;
-               if (same_src(ct, tuple)) {
+               if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
                        /* Copy source part from reply tuple. */
                        nf_ct_invert_tuplepr(result,
                                       &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
@@ -175,7 +177,7 @@ find_appropriate_src(struct net *net,
    the ip with the lowest src-ip/dst-ip/proto usage.
 */
 static void
-find_best_ips_proto(struct nf_conntrack_tuple *tuple,
+find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
                    const struct nf_nat_range *range,
                    const struct nf_conn *ct,
                    enum nf_nat_manip_type maniptype)
@@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
        maxip = ntohl(range->max_ip);
        j = jhash_2words((__force u32)tuple->src.u3.ip,
                         range->flags & IP_NAT_RANGE_PERSISTENT ?
-                               0 : (__force u32)tuple->dst.u3.ip, 0);
+                               0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
        j = ((u64)j * (maxip - minip + 1)) >> 32;
        *var_ipp = htonl(minip + j);
 }
@@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
 {
        struct net *net = nf_ct_net(ct);
        const struct nf_nat_protocol *proto;
+       u16 zone = nf_ct_zone(ct);
 
        /* 1) If this srcip/proto/src-proto-part is currently mapped,
           and that same mapping gives a unique tuple within the given
@@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
           manips not an issue.  */
        if (maniptype == IP_NAT_MANIP_SRC &&
            !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
-               if (find_appropriate_src(net, orig_tuple, tuple, range)) {
+               if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) {
                        pr_debug("get_unique_tuple: Found current src map\n");
                        if (!nf_nat_used_tuple(tuple, ct))
                                return;
@@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
        /* 2) Select the least-used IP/proto combination in the given
           range. */
        *tuple = *orig_tuple;
-       find_best_ips_proto(tuple, range, ct, maniptype);
+       find_best_ips_proto(zone, tuple, range, ct, maniptype);
 
        /* 3) The per-protocol part of the manip is made to map into
           the range to make a unique tuple. */
@@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct,
        if (have_to_hash) {
                unsigned int srchash;
 
-               srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+               srchash = hash_by_src(net, nf_ct_zone(ct),
+                                     &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
                spin_lock_bh(&nf_nat_lock);
                /* nf_conntrack_alter_reply might re-allocate exntension aera */
                nat = nfct_nat(ct);