[NETFILTER]: fix list traversal order in ctnetlink
authorPablo Neira Ayuso <pablo@eurodev.net>
Wed, 10 Aug 2005 03:06:42 +0000 (20:06 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 29 Aug 2005 22:40:25 +0000 (15:40 -0700)
Currently conntracks are inserted after the head. That means that
conntracks are sorted from the biggest to the smallest id. This happens
because we use list_prepend (list_add) instead list_add_tail. This can
result in problems during the list iteration.

                 list_for_each(i, &ip_conntrack_hash[cb->args[0]]) {
                         h = (struct ip_conntrack_tuple_hash *) i;
                         if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
                                 continue;
                         ct = tuplehash_to_ctrack(h);
                         if (ct->id <= *id)
                                 continue;

In that case just the first conntrack in the bucket will be dumped. To
fix this, we iterate the list from the tail to the head via
list_for_each_prev. Same thing for the list of expectations.

Signed-off-by: Pablo Neira Ayuso <pablo@eurodev.net>
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/netfilter/ip_conntrack_netlink.c

index e3ba449..1221a9c 100644 (file)
@@ -404,7 +404,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 
        read_lock_bh(&ip_conntrack_lock);
        for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
-               list_for_each(i, &ip_conntrack_hash[cb->args[0]]) {
+               list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
                        h = (struct ip_conntrack_tuple_hash *) i;
                        if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
                                continue;
@@ -441,7 +441,7 @@ ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
 
        write_lock_bh(&ip_conntrack_lock);
        for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
-               list_for_each(i, &ip_conntrack_hash[cb->args[0]]) {
+               list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
                        h = (struct ip_conntrack_tuple_hash *) i;
                        if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
                                continue;
@@ -1214,7 +1214,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
 
        read_lock_bh(&ip_conntrack_lock);
-       list_for_each(i, &ip_conntrack_expect_list) {
+       list_for_each_prev(i, &ip_conntrack_expect_list) {
                exp = (struct ip_conntrack_expect *) i;
                if (exp->id <= *id)
                        continue;