773311
From a60b2826bd4eb0144d2dc9b25b63b3a6ca5106c7 Mon Sep 17 00:00:00 2001
773311
From: Mark Michelson <mmichels@redhat.com>
773311
Date: Mon, 20 Apr 2020 09:25:09 -0400
773311
Subject: [PATCH 1/2] DNS: Make DNS lookups case insensitive.
773311
773311
From RFC 1035 Section 2.3.3:
773311
773311
"For all parts of the DNS that are part of the official protocol, all
773311
comparisons between character strings (e.g., labels, domain names, etc.)
773311
are done in a case-insensitive manner."
773311
773311
OVN was using case-sensitive lookups and therefore was not complying.
773311
This change makes lookups case insensitive by storing lowercase record
773311
names in the southbound database and converting incoming query names to
773311
lowercase.
773311
773311
Signed-off-by: Mark Michelson <mmichels@redhat.com>
773311
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819069
773311
Reported-by: Jianlin Shi <jishi@redhat.com>
773311
Acked-by: Numan Siddique <numans@ovn.org>
773311
---
773311
 controller/pinctrl.c |  7 ++++-
773311
 lib/ovn-util.c       | 15 +++++++++++
773311
 lib/ovn-util.h       |  5 ++++
773311
 northd/ovn-northd.c  | 15 ++++++++++-
773311
 ovn-sb.xml           |  3 ++-
773311
 tests/ovn.at         | 61 ++++++++++++++++++++++++++++++++------------
773311
 6 files changed, 87 insertions(+), 19 deletions(-)
773311
773311
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
773311
index 8703641c2..8592d4e3f 100644
773311
--- a/controller/pinctrl.c
773311
+++ b/controller/pinctrl.c
773311
@@ -2368,7 +2368,12 @@ pinctrl_handle_dns_lookup(
773311
         struct dns_data *d = iter->data;
773311
         for (size_t i = 0; i < d->n_dps; i++) {
773311
             if (d->dps[i] == dp_key) {
773311
-                answer_ips = smap_get(&d->records, ds_cstr(&query_name));
773311
+                /* DNS records in SBDB are stored in lowercase. Convert to
773311
+                 * lowercase to perform case insensitive lookup
773311
+                 */
773311
+                char *query_name_lower = str_tolower(ds_cstr(&query_name));
773311
+                answer_ips = smap_get(&d->records, query_name_lower);
773311
+                free(query_name_lower);
773311
                 if (answer_ips) {
773311
                     break;
773311
                 }
773311
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
773311
index 514e2489f..1b30c2e9a 100644
773311
--- a/lib/ovn-util.c
773311
+++ b/lib/ovn-util.c
773311
@@ -21,6 +21,7 @@
773311
 #include "openvswitch/ofp-parse.h"
773311
 #include "ovn-nb-idl.h"
773311
 #include "ovn-sb-idl.h"
773311
+#include <ctype.h>
773311
 
773311
 VLOG_DEFINE_THIS_MODULE(ovn_util);
773311
 
773311
@@ -550,3 +551,17 @@ ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2)
773311
             (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 :
773311
              IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6)));
773311
 }
773311
+
773311
+char *
773311
+str_tolower(const char *orig)
773311
+{
773311
+    char *copy = xmalloc(strlen(orig) + 1);
773311
+    char *p = copy;
773311
+
773311
+    while (*orig) {
773311
+        *p++ = tolower(*orig++);
773311
+    }
773311
+    *p = '\0';
773311
+
773311
+    return copy;
773311
+}
773311
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
773311
index 11238f61c..4076e8b9a 100644
773311
--- a/lib/ovn-util.h
773311
+++ b/lib/ovn-util.h
773311
@@ -124,4 +124,9 @@ struct v46_ip {
773311
 bool ip46_parse_cidr(const char *str, struct v46_ip *prefix,
773311
                      unsigned int *plen);
773311
 bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
773311
+
773311
+/* Returns a lowercase copy of orig.
773311
+ * Caller must free the returned string.
773311
+ */
773311
+char *str_tolower(const char *orig);
773311
 #endif
773311
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
773311
index f7d3988d7..515722c5d 100644
773311
--- a/northd/ovn-northd.c
773311
+++ b/northd/ovn-northd.c
773311
@@ -10698,7 +10698,20 @@ sync_dns_entries(struct northd_context *ctx, struct hmap *datapaths)
773311
             dns_info->sb_dns,
773311
             (struct sbrec_datapath_binding **)dns_info->sbs,
773311
             dns_info->n_sbs);
773311
-        sbrec_dns_set_records(dns_info->sb_dns, &dns_info->nb_dns->records);
773311
+
773311
+        /* DNS lookups are case-insensitive. Convert records to lowercase so
773311
+         * we can do consistent lookups when DNS requests arrive
773311
+         */
773311
+        struct smap lower_records = SMAP_INITIALIZER(&lower_records);
773311
+        struct smap_node *node;
773311
+        SMAP_FOR_EACH (node, &dns_info->nb_dns->records) {
773311
+            smap_add_nocopy(&lower_records, xstrdup(node->key),
773311
+                            str_tolower(node->value));
773311
+        }
773311
+
773311
+        sbrec_dns_set_records(dns_info->sb_dns, &lower_records);
773311
+
773311
+        smap_destroy(&lower_records);
773311
         free(dns_info->sbs);
773311
         free(dns_info);
773311
     }
773311
diff --git a/ovn-sb.xml b/ovn-sb.xml
773311
index 72466b97e..5f8da534c 100644
773311
--- a/ovn-sb.xml
773311
+++ b/ovn-sb.xml
773311
@@ -3597,7 +3597,8 @@ tcp.flags = RST;
773311
     <column name="records">
773311
       Key-value pair of DNS records with DNS query name as the key
773311
       and a string of IP address(es) separated by comma or space as the
773311
-      value.
773311
+      value. ovn-northd stores the DNS query name in all lowercase in order to
773311
+      facilitate case-insensitive lookups.
773311
 
773311
       

Example: "vm1.ovn.org" = "10.0.0.4 aef0::4"

773311
     </column>
773311
diff --git a/tests/ovn.at b/tests/ovn.at
773311
index 0f02e8144..b78637044 100644
773311
--- a/tests/ovn.at
773311
+++ b/tests/ovn.at
773311
@@ -8328,6 +8328,12 @@ set_dns_params() {
773311
         # IPv4 address - 10.0.0.4
773311
         expected_dns_answer=${query_name}00010001${ttl}00040a000004
773311
         ;;
773311
+    VM1)
773311
+        # VM1.OVN.ORG
773311
+        query_name=03564d31034f564e034f524700
773311
+        # IPv4 address - 10.0.0.4
773311
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
773311
+        ;;
773311
     vm2)
773311
         # vm2.ovn.org
773311
         query_name=03766d32036f766e036f726700
773311
@@ -8490,6 +8496,29 @@ reset_pcap_file hv1-vif2 hv1/vif2
773311
 rm -f 1.expected
773311
 rm -f 2.expected
773311
 
773311
+# Try vm1 again but an all-caps query name
773311
+
773311
+set_dns_params VM1
773311
+src_ip=`ip_to_hex 10 0 0 6`
773311
+dst_ip=`ip_to_hex 10 0 0 1`
773311
+dns_reply=1
773311
+test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
773311
+
773311
+# NXT_RESUMEs should be 3.
773311
+OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+
773311
+$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
+cat 2.expected | cut -c -48 > expout
773311
+AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
773311
+# Skipping the IPv4 checksum.
773311
+cat 2.expected | cut -c 53- > expout
773311
+AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
773311
+
773311
+reset_pcap_file hv1-vif1 hv1/vif1
773311
+reset_pcap_file hv1-vif2 hv1/vif2
773311
+rm -f 1.expected
773311
+rm -f 2.expected
773311
+
773311
 # Clear the query name options for ls1-lp2
773311
 ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org
773311
 
773311
@@ -8499,8 +8528,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=0
773311
 test_dns 1 f00000000001 f00000000002 $src_ip $dst_ip $dns_reply $dns_req_data
773311
 
773311
-# NXT_RESUMEs should be 3.
773311
-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 4.
773311
+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
773311
 AT_CHECK([cat 1.packets], [0], [])
773311
@@ -8521,8 +8550,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=0
773311
 test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
773311
 
773311
-# NXT_RESUMEs should be 3 only.
773311
-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 4 only.
773311
+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
 AT_CHECK([cat 2.packets], [0], [])
773311
@@ -8542,8 +8571,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=1
773311
 test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
773311
 
773311
-# NXT_RESUMEs should be 4.
773311
-OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 5.
773311
+OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
 cat 2.expected | cut -c -48 > expout
773311
@@ -8564,8 +8593,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=1
773311
 test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
773311
 
773311
-# NXT_RESUMEs should be 5.
773311
-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 6.
773311
+OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
 cat 2.expected | cut -c -48 > expout
773311
@@ -8586,8 +8615,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=0
773311
 test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
773311
 
773311
-# NXT_RESUMEs should be 6.
773311
-OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 7.
773311
+OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
 AT_CHECK([cat 2.packets], [0], [])
773311
@@ -8604,8 +8633,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=0
773311
 test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
773311
 
773311
-# NXT_RESUMEs should be 7.
773311
-OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 8.
773311
+OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
773311
 AT_CHECK([cat 2.packets], [0], [])
773311
@@ -8624,8 +8653,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
773311
 dns_reply=1
773311
 test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
773311
 
773311
-# NXT_RESUMEs should be 8.
773311
-OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 9.
773311
+OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
773311
 cat 1.expected | cut -c -48 > expout
773311
@@ -8646,8 +8675,8 @@ dst_ip=aef00000000000000000000000000001
773311
 dns_reply=1
773311
 test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
773311
 
773311
-# NXT_RESUMEs should be 9.
773311
-OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
+# NXT_RESUMEs should be 10
773311
+OVS_WAIT_UNTIL([test 10 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
773311
 
773311
 $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
773311
 # Skipping the UDP checksum.
773311
-- 
773311
2.25.1
773311