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 02f08e661d..0d8f0a4031 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 +check 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