diff --git a/components/mdns/examples/main/mdns_example_main.c b/components/mdns/examples/main/mdns_example_main.c index bd2cfe147..181dfed88 100644 --- a/components/mdns/examples/main/mdns_example_main.c +++ b/components/mdns/examples/main/mdns_example_main.c @@ -276,16 +276,15 @@ void app_main(void) * This is typically performed in "GOT_IP" event handler, but we call it here directly * since the `EXAMPLE_INTERFACE` netif is connected already, to keep the example simple. */ - ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4)); - ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4)); -#endif + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_ENABLE_IP6)); + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4 | MDNS_EVENT_ANNOUNCE_IP6)); #if defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES) - while (mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_IP4_REVERSE_LOOKUP) != ESP_OK) { - vTaskDelay(50 / portTICK_PERIOD_MS); - } + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP)); #endif +#endif // CONFIG_MDNS_ADD_CUSTOM_NETIF + initialise_button(); xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL); } diff --git a/components/mdns/examples/pytest_mdns.py b/components/mdns/examples/pytest_mdns.py index f13abc149..42364dfe3 100644 --- a/components/mdns/examples/pytest_mdns.py +++ b/components/mdns/examples/pytest_mdns.py @@ -120,10 +120,11 @@ def test_examples_protocol_mdns(dut): 2. get the dut host name (and IP address) 3. check the mdns name is accessible 4. check DUT output if mdns advertized host is resolved + 5. check if DUT responds to dig + 6. check the DUT is searchable via reverse IP lookup """ - specific_host = dut.expect(re.compile( - b'mdns hostname set to: \[(.*?)\]')).group(1).decode() # noqa: W605 + specific_host = dut.expect(r'mdns hostname set to: \[(.*?)\]')[1].decode() mdns_server_events = { 'stop': Event(), @@ -132,9 +133,14 @@ def test_examples_protocol_mdns(dut): } mdns_responder = Thread(target=mdns_server, args=(str(specific_host), mdns_server_events)) - ip_address = dut.expect( - re.compile(b'IPv4 address:([a-zA-Z0-9]*).*')).group(1).decode() - print('Connected to AP with IP: {}'.format(ip_address)) + ipv4 = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', + timeout=30)[1].decode() + ip_addresses = [ipv4] + if dut.app.sdkconfig.get('LWIP_IPV6') is True: + ipv6_r = r':'.join((r'[0-9a-fA-F]{4}', ) * 8) + ipv6 = dut.expect(ipv6_r, timeout=30)[0].decode() + ip_addresses.append(ipv6) + print('Connected with IP addresses: {}'.format(','.join(ip_addresses))) try: # 3. check the mdns name is accessible. mdns_responder.start() @@ -165,11 +171,25 @@ def test_examples_protocol_mdns(dut): ]) print('Resolving {} using "dig" succeeded with:\n{}'.format( specific_host, dig_output)) - if not ip_address.encode('utf-8') in dig_output: + if not ipv4.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)) + "Output should've contained DUT's IP address:{}".format(ipv4)) + # 6. check the DUT reverse lookup + if dut.app.sdkconfig.get('MDNS_RESPOND_REVERSE_QUERIES') is True: + for ip_address in ip_addresses: + dig_output = subprocess.check_output([ + 'dig', '+short', '-p', '5353', '@224.0.0.251', '-x', + '{}'.format(ip_address) + ]) + print('Reverse lookup for {} using "dig" succeeded with:\n{}'. + format(ip_address, dig_output)) + if specific_host not in dig_output.decode(): + raise ValueError( + 'Test has failed: Incorrectly resolved DUT IP address using dig' + "Output should've contained DUT's name:{}".format( + specific_host)) + finally: mdns_server_events['stop'].set() mdns_responder.join() diff --git a/components/mdns/examples/sdkconfig.ci.eth_custom_netif b/components/mdns/examples/sdkconfig.ci.eth_custom_netif index 56499bd43..b9d712041 100644 --- a/components/mdns/examples/sdkconfig.ci.eth_custom_netif +++ b/components/mdns/examples/sdkconfig.ci.eth_custom_netif @@ -6,6 +6,7 @@ CONFIG_MDNS_PREDEF_NETIF_STA=n CONFIG_MDNS_PREDEF_NETIF_AP=n CONFIG_MDNS_PREDEF_NETIF_ETH=n CONFIG_MDNS_ADD_CUSTOM_NETIF=y +CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_WIFI=n diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 36bb15565..1f5da25cd 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -437,8 +437,8 @@ static const uint8_t *_mdns_read_fqdn(const uint8_t *packet, const uint8_t *star if (name->parts == 1 && buf[0] != '_' && (strcasecmp(buf, MDNS_DEFAULT_DOMAIN) != 0) && (strcasecmp(buf, "arpa") != 0) - && (strcasecmp(buf, "ip6") != 0) #ifndef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + && (strcasecmp(buf, "ip6") != 0) && (strcasecmp(buf, "in-addr") != 0) #endif ) { @@ -1162,7 +1162,7 @@ static uint16_t _mdns_append_question(uint8_t *packet, uint16_t *index, mdns_out { uint8_t part_length; #ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES - if (q->host && strstr(q->host, "in-addr")) { + if (q->host && (strstr(q->host, "in-addr") || strstr(q->host, "ip6"))) { part_length = append_fqdn_dots(packet, index, q->host, false); if (!part_length) { return 0; @@ -1275,7 +1275,7 @@ static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_h */ static uint8_t _mdns_append_reverse_ptr_record(uint8_t *packet, uint16_t *index, const char *name) { - if (strstr(name, "in-addr") == NULL) { + if (strstr(name, "in-addr") == NULL && strstr(name, "ip6") == NULL) { return 0; } @@ -1339,7 +1339,8 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an if (answer->service) { return _mdns_append_service_ptr_answers(packet, index, answer->service, answer->flush, answer->bye); #ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES - } else if (answer->host && answer->host->hostname && strstr(answer->host->hostname, "in-addr")) { + } else if (answer->host && answer->host->hostname && + (strstr(answer->host->hostname, "in-addr") || strstr(answer->host->hostname, "ip6"))) { return _mdns_append_reverse_ptr_record(packet, index, answer->host->hostname) > 0; #endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ } else { @@ -3966,6 +3967,13 @@ void _mdns_disable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state = PCB_OFF; } +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +static inline char nibble_to_hex(int var) +{ + return var > 9 ? var - 10 + 'a' : var + '0'; +} +#endif + /** * @brief Performs interface changes based on system events or custom commands */ @@ -4007,6 +4015,32 @@ static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action) } } } + +#ifdef CONFIG_LWIP_IPV6 + if (action & MDNS_EVENT_IP6_REVERSE_LOOKUP) { + esp_ip6_addr_t addr6; + if (!esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(mdns_if), &addr6) && !_ipv6_address_is_zero(addr6)) { + uint8_t *paddr = (uint8_t *)&addr6.addr; + const char sub[] = "ip6"; + const size_t query_name_size = 4 * sizeof(addr6.addr) /* (2 nibbles + 2 dots)/per byte of IP address */ + sizeof(sub); + char *reverse_query_name = malloc(query_name_size); + if (reverse_query_name) { + char *ptr = &reverse_query_name[query_name_size]; // point to the end + memcpy(ptr - sizeof(sub), sub, sizeof(sub)); // copy the IP sub-domain + ptr -= sizeof(sub) + 1; // move before the sub-domain + while (reverse_query_name < ptr) { // continue populating reverse query from the end + *ptr-- = '.'; // nibble by nibble, until we reach the beginning + *ptr-- = nibble_to_hex(((*paddr) >> 4) & 0x0F); + *ptr-- = '.'; + *ptr-- = nibble_to_hex((*paddr) & 0x0F); + paddr++; + } + ESP_LOGD(TAG, "Registered reverse query: %s.arpa", reverse_query_name); + _mdns_delegate_hostname_add(reverse_query_name, NULL); + } + } + } +#endif /* CONFIG_LWIP_IPV6 */ #endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 26ecfecf0..885cef722 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -89,7 +89,11 @@ #define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing #define MDNS_ACTION_QUEUE_LEN 16 // Maximum actions pending to the server #define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record +#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES) +#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" ) +#else #define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto +#endif #define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto #define MDNS_MAX_PACKET_SIZE 1460 // Maximum size of mDNS outgoing packet diff --git a/components/mdns/tests/host_test/main/main.c b/components/mdns/tests/host_test/main/main.c index 5b3930743..0a1fa2522 100644 --- a/components/mdns/tests/host_test/main/main.c +++ b/components/mdns/tests/host_test/main/main.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) ESP_ERROR_CHECK(mdns_hostname_set(CONFIG_TEST_HOSTNAME)); ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_TEST_HOSTNAME); ESP_ERROR_CHECK(mdns_register_netif(sta)); - ESP_ERROR_CHECK(mdns_netif_action(sta, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_IP4_REVERSE_LOOKUP)); + ESP_ERROR_CHECK(mdns_netif_action(sta, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP)); #ifdef REGISTER_SERVICE //set default mDNS instance name