diff mbox series

[ovs-dev,v2] pinctrl: dns: Ignore additional records.

Message ID 20240209152117.957387-1-dceara@redhat.com
State Accepted
Headers show
Series [ovs-dev,v2] pinctrl: dns: Ignore additional records. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Dumitru Ceara Feb. 9, 2024, 3:21 p.m. UTC
EDNS is backwards compatible so it's safe to just ignore additional ARs.

Reported-at: https://github.com/ovn-org/ovn/issues/228
Reported-at: https://issues.redhat.com/browse/FDP-222
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
V2:
- Addressed Mark's comments:
  - fixed subject
  - added test
---
 controller/pinctrl.c | 20 ++++++++---------
 tests/ovn.at         | 51 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 10 deletions(-)

Comments

Mark Michelson Feb. 9, 2024, 7:34 p.m. UTC | #1
Thank you for the updates, Dumitru.

Acked-by: Mark Michelson <mmichels@redhat.com>

On 2/9/24 10:21, Dumitru Ceara wrote:
> EDNS is backwards compatible so it's safe to just ignore additional ARs.
> 
> Reported-at: https://github.com/ovn-org/ovn/issues/228
> Reported-at: https://issues.redhat.com/browse/FDP-222
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
> V2:
> - Addressed Mark's comments:
>    - fixed subject
>    - added test
> ---
>   controller/pinctrl.c | 20 ++++++++---------
>   tests/ovn.at         | 51 ++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 61 insertions(+), 10 deletions(-)
> 
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index faa3f92260..98b29de9ff 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -2887,6 +2887,7 @@ dns_build_ptr_answer(
>   }
>   
>   #define DNS_RCODE_SERVER_REFUSE 0x5
> +#define DNS_QUERY_TYPE_CLASS_LEN (2 * sizeof(ovs_be16))
>   
>   /* Called with in the pinctrl_handler thread context. */
>   static void
> @@ -2950,18 +2951,13 @@ pinctrl_handle_dns_lookup(
>           goto exit;
>       }
>   
> -    /* Check if there is an additional record present, which is unsupported */
> -    if (in_dns_header->arcount) {
> -        VLOG_DBG_RL(&rl, "Received DNS query with additional records, which"
> -                    " is unsupported");
> -        goto exit;
> -    }
> -
>       struct udp_header *in_udp = dp_packet_l4(pkt_in);
>       size_t udp_len = ntohs(in_udp->udp_len);
>       size_t l4_len = dp_packet_l4_size(pkt_in);
> +    uint8_t *l4_start = (uint8_t *) in_udp;
>       uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len);
>       uint8_t *in_dns_data = (uint8_t *)(in_dns_header + 1);
> +    uint8_t *in_dns_data_start = in_dns_data;
>       uint8_t *in_queryname = in_dns_data;
>       uint16_t idx = 0;
>       struct ds query_name;
> @@ -2985,7 +2981,7 @@ pinctrl_handle_dns_lookup(
>       in_dns_data += idx;
>   
>       /* Query should have TYPE and CLASS fields */
> -    if (in_dns_data + (2 * sizeof(ovs_be16)) > end) {
> +    if (in_dns_data + DNS_QUERY_TYPE_CLASS_LEN > end) {
>           ds_destroy(&query_name);
>           goto exit;
>       }
> @@ -2999,6 +2995,10 @@ pinctrl_handle_dns_lookup(
>           goto exit;
>       }
>   
> +    uint8_t *rest = in_dns_data + DNS_QUERY_TYPE_CLASS_LEN;
> +    uint32_t query_size = rest - in_dns_data_start;
> +    uint32_t query_l4_size = rest - l4_start;
> +
>       uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata);
>       const char *answer_data = NULL;
>       bool ovn_owned = false;
> @@ -3081,7 +3081,7 @@ pinctrl_handle_dns_lookup(
>           goto exit;
>       }
>   
> -    uint16_t new_l4_size = ntohs(in_udp->udp_len) +  dns_answer.size;
> +    uint16_t new_l4_size = query_l4_size + dns_answer.size;
>       size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
>       struct dp_packet pkt_out;
>       dp_packet_init(&pkt_out, new_packet_size);
> @@ -3118,7 +3118,7 @@ pinctrl_handle_dns_lookup(
>       out_dns_header->arcount = 0;
>   
>       /* Copy the Query section. */
> -    dp_packet_put(&pkt_out, dp_packet_data(pkt_in), dp_packet_size(pkt_in));
> +    dp_packet_put(&pkt_out, dp_packet_data(pkt_in), query_size);
>   
>       /* Copy the answer sections. */
>       dp_packet_put(&pkt_out, dns_answer.data, dns_answer.size);
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 2cf335cf45..6b0b80bfc1 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -11455,6 +11455,57 @@ OVN_CLEANUP([hv1])
>   AT_CLEANUP
>   ])
>   
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([dns lookup : EDNS])
> +AT_SKIP_IF([test $HAVE_SCAPY = no])
> +ovn_start
> +
> +check ovn-nbctl ls-add ls \
> +    -- lsp-add ls lsp     \
> +    -- lsp-set-addresses lsp "00:00:00:00:00:01 10.0.0.1"
> +
> +d=$(ovn-nbctl create dns records={})
> +
> +check ovn-nbctl set dns $d records:foo.ovn.org="10.0.0.42"
> +check ovn-nbctl set Logical_switch ls dns_records="$d"
> +
> +net_add n1
> +sim_add hv1
> +
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +ovs-vsctl -- add-port br-int hv1-vif1 -- \
> +    set interface hv1-vif1 external-ids:iface-id=lsp \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap
> +
> +OVN_POPULATE_ARP
> +wait_for_ports_up
> +check ovn-nbctl --wait=hv sync
> +
> +dns_req=$(fmt_pkt "Ether(dst='00:00:00:00:00:02', src='00:00:00:00:00:01') / \
> +                   IP(dst='10.0.0.254', src='10.0.0.1') / \
> +                   UDP(sport=42424, dport=53) / \
> +                   DNS(rd=1, qd=DNSQR(qname='foo.ovn.org'), arcount=1, ar=[ \
> +                       DNSRR(type='OPT', rclass=4096, \
> +                             rdata=EDNS0ClientSubnet(source_plen=24, \
> +                                                     address='10.0.0.1'))])")
> +dns_reply=$(fmt_pkt "Ether(dst='00:00:00:00:00:01', src='00:00:00:00:00:02') / \
> +                     IP(dst='10.0.0.1', src='10.0.0.254') / \
> +                     UDP(sport=53, dport=42424,chksum=0) / \
> +                     DNS(qr=1, qd=DNSQR(qname='foo.ovn.org'), \
> +                         an=DNSRR(rrname='foo.ovn.org', type='A', ttl=3600, \
> +                                  rdata='10.0.0.42'))")
> +echo ${dns_reply} > expected
> +
> +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 ${dns_req}
> +OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv1/vif1-tx.pcap], [expected])
> +
> +OVN_CLEANUP([hv1])
> +AT_CLEANUP
> +])
> +
>   OVN_FOR_EACH_NORTHD([
>   AT_SETUP([4 HV, 1 LS, 1 LR, packet test with HA distributed router gateway port])
>   ovn_start
Dumitru Ceara Feb. 12, 2024, 2:55 p.m. UTC | #2
On 2/9/24 20:34, Mark Michelson wrote:
> Thank you for the updates, Dumitru.
> 
> Acked-by: Mark Michelson <mmichels@redhat.com>
> 

Thanks, Mark, applied to main and backported to all stable branches down
to 22.03.

Regards,
Dumitru
diff mbox series

Patch

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index faa3f92260..98b29de9ff 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -2887,6 +2887,7 @@  dns_build_ptr_answer(
 }
 
 #define DNS_RCODE_SERVER_REFUSE 0x5
+#define DNS_QUERY_TYPE_CLASS_LEN (2 * sizeof(ovs_be16))
 
 /* Called with in the pinctrl_handler thread context. */
 static void
@@ -2950,18 +2951,13 @@  pinctrl_handle_dns_lookup(
         goto exit;
     }
 
-    /* Check if there is an additional record present, which is unsupported */
-    if (in_dns_header->arcount) {
-        VLOG_DBG_RL(&rl, "Received DNS query with additional records, which"
-                    " is unsupported");
-        goto exit;
-    }
-
     struct udp_header *in_udp = dp_packet_l4(pkt_in);
     size_t udp_len = ntohs(in_udp->udp_len);
     size_t l4_len = dp_packet_l4_size(pkt_in);
+    uint8_t *l4_start = (uint8_t *) in_udp;
     uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len);
     uint8_t *in_dns_data = (uint8_t *)(in_dns_header + 1);
+    uint8_t *in_dns_data_start = in_dns_data;
     uint8_t *in_queryname = in_dns_data;
     uint16_t idx = 0;
     struct ds query_name;
@@ -2985,7 +2981,7 @@  pinctrl_handle_dns_lookup(
     in_dns_data += idx;
 
     /* Query should have TYPE and CLASS fields */
-    if (in_dns_data + (2 * sizeof(ovs_be16)) > end) {
+    if (in_dns_data + DNS_QUERY_TYPE_CLASS_LEN > end) {
         ds_destroy(&query_name);
         goto exit;
     }
@@ -2999,6 +2995,10 @@  pinctrl_handle_dns_lookup(
         goto exit;
     }
 
+    uint8_t *rest = in_dns_data + DNS_QUERY_TYPE_CLASS_LEN;
+    uint32_t query_size = rest - in_dns_data_start;
+    uint32_t query_l4_size = rest - l4_start;
+
     uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata);
     const char *answer_data = NULL;
     bool ovn_owned = false;
@@ -3081,7 +3081,7 @@  pinctrl_handle_dns_lookup(
         goto exit;
     }
 
-    uint16_t new_l4_size = ntohs(in_udp->udp_len) +  dns_answer.size;
+    uint16_t new_l4_size = query_l4_size + dns_answer.size;
     size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
     struct dp_packet pkt_out;
     dp_packet_init(&pkt_out, new_packet_size);
@@ -3118,7 +3118,7 @@  pinctrl_handle_dns_lookup(
     out_dns_header->arcount = 0;
 
     /* Copy the Query section. */
-    dp_packet_put(&pkt_out, dp_packet_data(pkt_in), dp_packet_size(pkt_in));
+    dp_packet_put(&pkt_out, dp_packet_data(pkt_in), query_size);
 
     /* Copy the answer sections. */
     dp_packet_put(&pkt_out, dns_answer.data, dns_answer.size);
diff --git a/tests/ovn.at b/tests/ovn.at
index 2cf335cf45..6b0b80bfc1 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -11455,6 +11455,57 @@  OVN_CLEANUP([hv1])
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([dns lookup : EDNS])
+AT_SKIP_IF([test $HAVE_SCAPY = no])
+ovn_start
+
+check ovn-nbctl ls-add ls \
+    -- lsp-add ls lsp     \
+    -- lsp-set-addresses lsp "00:00:00:00:00:01 10.0.0.1"
+
+d=$(ovn-nbctl create dns records={})
+
+check ovn-nbctl set dns $d records:foo.ovn.org="10.0.0.42"
+check ovn-nbctl set Logical_switch ls dns_records="$d"
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+    set interface hv1-vif1 external-ids:iface-id=lsp \
+    options:tx_pcap=hv1/vif1-tx.pcap \
+    options:rxq_pcap=hv1/vif1-rx.pcap
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+dns_req=$(fmt_pkt "Ether(dst='00:00:00:00:00:02', src='00:00:00:00:00:01') / \
+                   IP(dst='10.0.0.254', src='10.0.0.1') / \
+                   UDP(sport=42424, dport=53) / \
+                   DNS(rd=1, qd=DNSQR(qname='foo.ovn.org'), arcount=1, ar=[ \
+                       DNSRR(type='OPT', rclass=4096, \
+                             rdata=EDNS0ClientSubnet(source_plen=24, \
+                                                     address='10.0.0.1'))])")
+dns_reply=$(fmt_pkt "Ether(dst='00:00:00:00:00:01', src='00:00:00:00:00:02') / \
+                     IP(dst='10.0.0.1', src='10.0.0.254') / \
+                     UDP(sport=53, dport=42424,chksum=0) / \
+                     DNS(qr=1, qd=DNSQR(qname='foo.ovn.org'), \
+                         an=DNSRR(rrname='foo.ovn.org', type='A', ttl=3600, \
+                                  rdata='10.0.0.42'))")
+echo ${dns_reply} > expected
+
+as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 ${dns_req}
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv1/vif1-tx.pcap], [expected])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([4 HV, 1 LS, 1 LR, packet test with HA distributed router gateway port])
 ovn_start