From e2b314522e2d7545f6b6f3230a7d44dbe9bdd71a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 27 Jul 2020 07:14:34 +0200 Subject: [PATCH 1/4] mdns: Fix include query ID in reponses Closes https://github.com/espressif/esp-idf/issues/5574 --- components/mdns/mdns.c | 3 +++ components/mdns/private_include/mdns_private.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 711de2a451..750456c7ea 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -980,6 +980,7 @@ static void _mdns_dispatch_tx_packet(mdns_tx_packet_t * p) uint8_t count; _mdns_set_u16(packet, MDNS_HEAD_FLAGS_OFFSET, p->flags); + _mdns_set_u16(packet, MDNS_HEAD_ID_OFFSET, p->id); count = 0; q = p->questions; @@ -1259,6 +1260,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed } packet->flags = MDNS_FLAGS_AUTHORITATIVE; packet->distributed = parsed_packet->distributed; + packet->id = parsed_packet->id; mdns_parsed_question_t * q = parsed_packet->questions; while (q) { @@ -2662,6 +2664,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) parsed_packet->multicast = packet->multicast; parsed_packet->authoritative = header.flags.value == MDNS_FLAGS_AUTHORITATIVE; parsed_packet->distributed = header.flags.value == MDNS_FLAGS_DISTRIBUTED; + parsed_packet->id = header.id; ip_addr_copy(parsed_packet->src, packet->src); parsed_packet->src_port = packet->src_port; diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index f572cc2330..935c9546fa 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -236,6 +236,7 @@ typedef struct { uint8_t distributed; mdns_parsed_question_t * questions; mdns_parsed_record_t * records; + uint16_t id; } mdns_parsed_packet_t; typedef struct { @@ -304,6 +305,7 @@ typedef struct mdns_tx_packet_s { mdns_out_answer_t * servers; mdns_out_answer_t * additional; bool queued; + uint16_t id; } mdns_tx_packet_t; typedef struct { From 12e86a7c1b58470f1ec41a68cdc2d011a2699ec9 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 28 Jul 2020 09:06:12 +0200 Subject: [PATCH 2/4] mdns: Support queries in responses in mDNS non-strict mode By default adds original queries to responses in order to be resolved by some resolvers, such as lwIP mdns library. This functionality however is discouraged by the RFC6762, so it could be disabled in menuconfig if MDNS_STRICT_MODE configured Closes https://github.com/espressif/esp-idf/issues/5521 --- components/mdns/mdns.c | 11 +++++++++++ components/mdns/private_include/mdns_private.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 750456c7ea..debc026511 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1313,6 +1313,17 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed _mdns_free_tx_packet(packet); return; } +#ifdef MDNS_REPEAT_QUERY_IN_RESPONSE + mdns_out_question_t * out_question = malloc(sizeof(mdns_out_question_t)); + if (out_question == NULL) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return; + } + memcpy(out_question, q, sizeof(mdns_out_question_t)); + out_question->next = NULL; + queueToEnd(mdns_out_question_t, packet->questions, out_question); +#endif // MDNS_REPEAT_QUERY_IN_RESPONSE } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, send_flush, false)) { _mdns_free_tx_packet(packet); return; diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 935c9546fa..b4ad03df49 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -23,6 +23,22 @@ #define _mdns_dbg_printf(...) printf(__VA_ARGS__) #endif +/** mDNS strict mode: Set this to 1 for the mDNS library to strictly follow the RFC6762: + * Strict features: + * - to do not set original questions in response packets per RFC6762, sec 6 + * + * The actual configuration is 0, i.e. non-strict mode, since some implementations, + * such as lwIP mdns resolver (used by standard POSIX API like getaddrinfo, gethostbyname) + * could not correctly resolve advertised names. + */ +#define MDNS_STRICT_MODE 0 + +#if !MDNS_STRICT_MODE +/* mDNS responders sometimes repeat queries in responses + * but according to RFC6762, sec 6: Responses MUST NOT contain + * any item in question field */ +#define MDNS_REPEAT_QUERY_IN_RESPONSE 1 +#endif /** The maximum number of services */ #define MDNS_MAX_SERVICES CONFIG_MDNS_MAX_SERVICES From 2afcd778748bb7d6fe489982c864b83d117a346b Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 29 Jul 2020 10:18:34 +0200 Subject: [PATCH 3/4] examples: Common connect component: Unregister shutdown handler on disconnection To be able to connect smoothly after disconnecting, we have to unregister all handlers including shutdown handler on disconnection --- examples/common_components/protocol_examples_common/connect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 9713edda2c..ceddf97d20 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -105,6 +105,7 @@ esp_err_t example_disconnect(void) stop(); ESP_LOGI(TAG, "Disconnected from %s", s_connection_name); s_connection_name = NULL; + ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&stop)); return ESP_OK; } From fcfc04c42a2047be7661c37fb4aa1a29f105b2d0 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 30 Jul 2020 16:12:37 +0200 Subject: [PATCH 4/4] mdns test: Add test to resolve esp32 hostname with DiG --- examples/protocols/mdns/mdns_example_test.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/protocols/mdns/mdns_example_test.py b/examples/protocols/mdns/mdns_example_test.py index af897bb799..61bcae9d81 100644 --- a/examples/protocols/mdns/mdns_example_test.py +++ b/examples/protocols/mdns/mdns_example_test.py @@ -6,12 +6,11 @@ import struct import dpkt import dpkt.dns from threading import Thread, Event +import subprocess from tiny_test_fw import DUT import ttfw_idf -# g_run_server = True -# g_done = False stop_mdns_server = Event() esp_answered = Event() @@ -112,7 +111,8 @@ def test_examples_protocol_mdns(env, extra_data): thread1 = Thread(target=mdns_server, args=(specific_host,)) thread1.start() try: - dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30) + ip_address = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)[0] + print("Connected to AP with IP: {}".format(ip_address)) except DUT.ExpectTimeout: stop_mdns_server.set() thread1.join() @@ -125,6 +125,13 @@ def test_examples_protocol_mdns(env, extra_data): dut1.expect(re.compile(r"mdns-test: Query A: tinytester.local resolved to: 127.0.0.1"), timeout=30) dut1.expect(re.compile(r"mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1"), timeout=30) dut1.expect(re.compile(r"mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1"), timeout=30) + # 5. check the DUT answers to `dig` command + dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251', + '{}.local'.format(specific_host)]) + print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output)) + if not ip_address.encode('utf-8') in dig_output: + raise ValueError("Test has failed: Incorrectly resolved DUT hostname using dig" + "Output should've contained DUT's IP address:{}".format(ip_address)) finally: stop_mdns_server.set() thread1.join()