[ovs-dev,v4,2/2] conntrack: Lookup only 'UNNAT conns' in 'nat_clean()'.

Message ID 1552538743-31392-2-git-send-email-dlu998@gmail.com
State New
Headers show
Series
  • [ovs-dev,v4,1/2] conntrack: Fix race for NAT cleanup.
Related show

Commit Message

Darrell Ball March 14, 2019, 4:45 a.m.
When freeing 'UNNAT conns', lookup only 'UNNAT conns' to
protect against possible address overlap with 'default
conns' during a DOS attempt.  This is very unlikely, but
protection is simple.

Signed-off-by: Darrell Ball <dlu998@gmail.com>
---

This patch is targeted for earlier releases as new RCU patches
inherently don't have this race.

v1-v4: no change to this patch.

 lib/conntrack.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 96d7db8..2bc2839 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -773,6 +773,22 @@  conn_lookup_any(const struct conn_key *key,
     return conn;
 }
 
+/* This function is called with the bucket lock held. */
+static struct conn *
+conn_lookup_unnat(const struct conn_key *key,
+                  const struct conntrack_bucket *ctb, uint32_t hash)
+{
+    struct conn *conn = NULL;
+
+    HMAP_FOR_EACH_WITH_HASH (conn, node, hash, &ctb->connections) {
+        if (!conn_key_cmp(&conn->key, key)
+            && conn->conn_type == CT_CONN_TYPE_UN_NAT) {
+            break;
+        }
+    }
+    return conn;
+}
+
 static void
 conn_seq_skew_set(struct conntrack *ct, const struct conn_key *key,
                   long long now, int seq_skew, bool seq_skew_dir)
@@ -796,12 +812,13 @@  nat_clean(struct conntrack *ct, struct conn *conn,
     nat_conn_keys_remove(&ct->nat_conn_keys, &conn->rev_key, ct->hash_basis);
     ct_rwlock_unlock(&ct->resources_lock);
     ct_lock_unlock(&ctb->lock);
-    unsigned bucket_rev_conn =
-        hash_to_bucket(conn_key_hash(&conn->rev_key, ct->hash_basis));
+    uint32_t hash = conn_key_hash(&conn->rev_key, ct->hash_basis);
+    unsigned bucket_rev_conn = hash_to_bucket(hash);
     ct_lock_lock(&ct->buckets[bucket_rev_conn].lock);
     ct_rwlock_wrlock(&ct->resources_lock);
-    long long now = time_msec();
-    struct conn *rev_conn = conn_lookup(ct, &conn->rev_key, now);
+    struct conn *rev_conn = conn_lookup_unnat(&conn->rev_key,
+                                              &ct->buckets[bucket_rev_conn],
+                                              hash);
     struct nat_conn_key_node *nat_conn_key_node =
         nat_conn_keys_lookup(&ct->nat_conn_keys, &conn->rev_key,
                              ct->hash_basis);