vserver 1.9.3
[linux-2.6.git] / net / ipv4 / netfilter / ip_nat_core.c
index 1c6b781..1ecc3f2 100644 (file)
@@ -48,10 +48,8 @@ static unsigned int ip_nat_htable_size;
 
 static struct list_head *bysource;
 static struct list_head *byipsproto;
-LIST_HEAD(protos);
-LIST_HEAD(helpers);
+struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
 
-extern struct ip_nat_protocol unknown_nat_protocol;
 
 /* We keep extra hashes for each conntrack, for fast searching. */
 static inline size_t
@@ -78,9 +76,6 @@ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
        if (!info->initialized)
                return;
 
-       IP_NF_ASSERT(info->bysource.conntrack);
-       IP_NF_ASSERT(info->byipsproto.conntrack);
-
        hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
                         conn->tuplehash[IP_CT_DIR_ORIGINAL]
                         .tuple.dst.protonum);
@@ -91,8 +86,8 @@ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
                              .tuple.dst.protonum);
 
        WRITE_LOCK(&ip_nat_lock);
-       LIST_DELETE(&bysource[hs], &info->bysource);
-       LIST_DELETE(&byipsproto[hp], &info->byipsproto);
+       list_del(&info->bysource);
+       list_del(&info->byipsproto);
        WRITE_UNLOCK(&ip_nat_lock);
 }
 
@@ -107,23 +102,6 @@ ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
                                      oldcheck^0xFFFF));
 }
 
-static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
-{
-       return i->protonum == proto;
-}
-
-struct ip_nat_protocol *
-find_nat_proto(u_int16_t protonum)
-{
-       struct ip_nat_protocol *i;
-
-       MUST_BE_READ_LOCKED(&ip_nat_lock);
-       i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
-       if (!i)
-               i = &unknown_nat_protocol;
-       return i;
-}
-
 /* Is this tuple already taken? (not by us) */
 int
 ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
@@ -146,7 +124,7 @@ in_range(const struct ip_conntrack_tuple *tuple,
         const struct ip_conntrack_manip *manip,
         const struct ip_nat_multi_range *mr)
 {
-       struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
+       struct ip_nat_protocol *proto = ip_nat_find_proto(tuple->dst.protonum);
        unsigned int i;
        struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
 
@@ -172,20 +150,18 @@ in_range(const struct ip_conntrack_tuple *tuple,
 }
 
 static inline int
-src_cmp(const struct ip_nat_hash *i,
+src_cmp(const struct ip_conntrack *ct,
        const struct ip_conntrack_tuple *tuple,
        const struct ip_nat_multi_range *mr)
 {
-       return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+       return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
                == tuple->dst.protonum
-               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
+               && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
                == tuple->src.ip
-               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
+               && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
                == tuple->src.u.all
                && in_range(tuple,
-                           &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-                           .tuple.src,
-                           mr));
+                           &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src, mr));
 }
 
 /* Only called for SRC manip */
@@ -194,14 +170,13 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple,
                     const struct ip_nat_multi_range *mr)
 {
        unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
-       struct ip_nat_hash *i;
+       struct ip_conntrack *ct;
 
        MUST_BE_READ_LOCKED(&ip_nat_lock);
-       i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
-       if (i)
-               return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
-       else
-               return NULL;
+       list_for_each_entry(ct, &bysource[h], nat.info.bysource)
+               if (src_cmp(ct, tuple, mr))
+                       return &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
+       return NULL;
 }
 
 #ifdef CONFIG_IP_NF_NAT_LOCAL
@@ -227,19 +202,17 @@ do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
 #endif
 
 /* Simple way to iterate through all. */
-static inline int fake_cmp(const struct ip_nat_hash *i,
+static inline int fake_cmp(const struct ip_conntrack *ct,
                           u_int32_t src, u_int32_t dst, u_int16_t protonum,
-                          unsigned int *score,
-                          const struct ip_conntrack *conntrack)
+                          unsigned int *score, const struct ip_conntrack *ct2)
 {
        /* Compare backwards: we're dealing with OUTGOING tuples, and
            inside the conntrack is the REPLY tuple.  Don't count this
            conntrack. */
-       if (i->conntrack != conntrack
-           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
-           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
-           && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
-               == protonum))
+       if (ct != ct2
+           && ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
+           && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
+           && (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum == protonum))
                (*score)++;
        return 0;
 }
@@ -248,13 +221,14 @@ static inline unsigned int
 count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
           const struct ip_conntrack *conntrack)
 {
+       struct ip_conntrack *ct;
        unsigned int score = 0;
        unsigned int h;
 
        MUST_BE_READ_LOCKED(&ip_nat_lock);
        h = hash_by_ipsproto(src, dst, protonum);
-       LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
-                 src, dst, protonum, &score, conntrack);
+       list_for_each_entry(ct, &byipsproto[h], nat.info.byipsproto)
+               fake_cmp(ct, src, dst, protonum, &score, conntrack);
 
        return score;
 }
@@ -402,7 +376,7 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
                 unsigned int hooknum)
 {
        struct ip_nat_protocol *proto
-               = find_nat_proto(orig_tuple->dst.protonum);
+               = ip_nat_find_proto(orig_tuple->dst.protonum);
        struct ip_nat_range *rptr;
        unsigned int i;
        int ret;
@@ -498,13 +472,6 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
        return ret;
 }
 
-static inline int
-helper_cmp(const struct ip_nat_helper *helper,
-          const struct ip_conntrack_tuple *tuple)
-{
-       return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
-}
-
 /* Where to manip the reply packets (will be reverse manip). */
 static unsigned int opposite_hook[NF_IP_NUMHOOKS]
 = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
@@ -643,18 +610,15 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
 
        /* If there's a helper, assign it; based on new tuple. */
        if (!conntrack->master)
-               info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-                                        &reply);
+               info->helper = __ip_nat_find_helper(&reply);
 
        /* It's done. */
        info->initialized |= (1 << HOOK2MANIP(hooknum));
 
-       if (in_hashes) {
-               IP_NF_ASSERT(info->bysource.conntrack);
+       if (in_hashes)
                replace_in_hashes(conntrack, info);
-       } else {
+       else
                place_in_hashes(conntrack, info);
-       }
 
        return NF_ACCEPT;
 }
@@ -678,14 +642,9 @@ void replace_in_hashes(struct ip_conntrack *conntrack,
                                   conntrack->tuplehash[IP_CT_DIR_REPLY]
                                   .tuple.dst.protonum);
 
-       IP_NF_ASSERT(info->bysource.conntrack == conntrack);
        MUST_BE_WRITE_LOCKED(&ip_nat_lock);
-
-       list_del(&info->bysource.list);
-       list_del(&info->byipsproto.list);
-
-       list_prepend(&bysource[srchash], &info->bysource);
-       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
+       list_move(&info->bysource, &bysource[srchash]);
+       list_move(&info->byipsproto, &byipsproto[ipsprotohash]);
 }
 
 void place_in_hashes(struct ip_conntrack *conntrack,
@@ -706,14 +665,9 @@ void place_in_hashes(struct ip_conntrack *conntrack,
                                   conntrack->tuplehash[IP_CT_DIR_REPLY]
                                   .tuple.dst.protonum);
 
-       IP_NF_ASSERT(!info->bysource.conntrack);
-
        MUST_BE_WRITE_LOCKED(&ip_nat_lock);
-       info->byipsproto.conntrack = conntrack;
-       info->bysource.conntrack = conntrack;
-
-       list_prepend(&bysource[srchash], &info->bysource);
-       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
+       list_add(&info->bysource, &bysource[srchash]);
+       list_add(&info->byipsproto, &byipsproto[ipsprotohash]);
 }
 
 /* Returns true if succeeded. */
@@ -733,9 +687,8 @@ manip_pkt(u_int16_t proto,
        iph = (void *)(*pskb)->data + iphdroff;
 
        /* Manipulate protcol part. */
-       if (!find_nat_proto(proto)->manip_pkt(pskb,
-                                             iphdroff + iph->ihl*4,
-                                             manip, maniptype))
+       if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4,
+                                                manip, maniptype))
                return 0;
 
        iph = (void *)(*pskb)->data + iphdroff;
@@ -759,7 +712,7 @@ static inline int exp_for_packet(struct ip_conntrack_expect *exp,
        int ret = 1;
 
        MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-       proto = __ip_ct_find_proto(skb->nh.iph->protocol);
+       proto = ip_ct_find_proto(skb->nh.iph->protocol);
        if (proto->exp_matches_pkt)
                ret = proto->exp_matches_pkt(exp, skb);
 
@@ -899,12 +852,8 @@ icmp_reply_translation(struct sk_buff **pskb,
        }
 
        /* Must be RELATED */
-       IP_NF_ASSERT((*pskb)->nfct
-                    - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos
-                    == IP_CT_RELATED
-                    || (*pskb)->nfct
-                    - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos
-                    == IP_CT_RELATED+IP_CT_IS_REPLY);
+       IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
+                    (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
 
        /* Redirects on non-null nats must be dropped, else they'll
            start talking to each other without our translation, and be
@@ -1004,9 +953,11 @@ int __init ip_nat_init(void)
 
        /* Sew in builtin protocols. */
        WRITE_LOCK(&ip_nat_lock);
-       list_append(&protos, &ip_nat_protocol_tcp);
-       list_append(&protos, &ip_nat_protocol_udp);
-       list_append(&protos, &ip_nat_protocol_icmp);
+       for (i = 0; i < MAX_IP_NAT_PROTO; i++)
+               ip_nat_protos[i] = &ip_nat_unknown_protocol;
+       ip_nat_protos[IPPROTO_TCP] = &ip_nat_protocol_tcp;
+       ip_nat_protos[IPPROTO_UDP] = &ip_nat_protocol_udp;
+       ip_nat_protos[IPPROTO_ICMP] = &ip_nat_protocol_icmp;
        WRITE_UNLOCK(&ip_nat_lock);
 
        for (i = 0; i < ip_nat_htable_size; i++) {