diff --git a/.github/workflows/host-test.yml b/.github/workflows/host-test.yml index 91ef93536..d823d38b8 100644 --- a/.github/workflows/host-test.yml +++ b/.github/workflows/host-test.yml @@ -57,4 +57,7 @@ jobs: . ${IDF_PATH}/export.sh cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/host_test idf.py build - ./build/mdns_host.elf & dig +short -p 5353 @224.0.0.251 myesp.local + ./build/mdns_host.elf & + dig +short -p 5353 @224.0.0.251 myesp.local > ip.txt + cat ip.txt | xargs dig +short -p 5353 @224.0.0.251 -x + cat ip.txt diff --git a/components/mdns/Kconfig b/components/mdns/Kconfig index 37b046a8a..53fb79ee5 100644 --- a/components/mdns/Kconfig +++ b/components/mdns/Kconfig @@ -95,6 +95,13 @@ menu "mDNS" help Enable for the library to log received and sent mDNS packets to stdout. + config MDNS_RESPOND_REVERSE_QUERIES + bool "Enable responding to IPv4 reverse queries" + default n + help + Enables support for IPv4 reverse lookup. If enabled, the mDNS library + response to PTR queries of "A.B.C.D.in-addr.arpa" type. + config MDNS_MULTIPLE_INSTANCE bool "Multiple instances under the same service type" default y diff --git a/components/mdns/examples/main/mdns_example_main.c b/components/mdns/examples/main/mdns_example_main.c index d0a393c9a..bd2cfe147 100644 --- a/components/mdns/examples/main/mdns_example_main.c +++ b/components/mdns/examples/main/mdns_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -279,6 +279,13 @@ void app_main(void) 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 + +#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); + } +#endif + initialise_button(); xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL); } diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index fd6186276..d6a3f150b 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -34,6 +34,8 @@ typedef enum { MDNS_EVENT_ANNOUNCE_IP6 = 1 << 4, MDNS_EVENT_DISABLE_IP4 = 1 << 5, MDNS_EVENT_DISABLE_IP6 = 1 << 6, + MDNS_EVENT_IP4_REVERSE_LOOKUP = 1 << 7, + MDNS_EVENT_IP6_REVERSE_LOOKUP = 1 << 8, } mdns_event_actions_t; /** diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 31408e63b..8c10cb1a3 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -17,9 +17,7 @@ #include "mdns_networking.h" #include "esp_log.h" #include "esp_random.h" -#if __has_include("bsd/string.h") -#include "bsd/string.h" -#endif + #if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH #include "esp_eth.h" #endif @@ -439,7 +437,11 @@ 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)) { + && (strcasecmp(buf, "ip6") != 0) +#ifndef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + && (strcasecmp(buf, "in-addr") != 0) +#endif + ) { strlcat(name->host, ".", sizeof(name->host)); strlcat(name->host, buf, sizeof(name->host)); } else if (strcasecmp(buf, MDNS_SUB_STR) == 0) { @@ -643,6 +645,60 @@ static inline int append_one_txt_record_entry(uint8_t *packet, uint16_t *index, return len + 1; } +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +static inline int append_single_str(uint8_t *packet, uint16_t *index, const char *str, int len) +{ + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + if (!_mdns_append_u8(packet, index, len)) { + return 0; + } + memcpy(packet + *index, str, len); + *index += len; + return *index; +} + +/** + * @brief appends FQDN to a packet from hostname separated by dots. This API works the same way as + * _mdns_append_fqdn(), but refrains from DNS compression (as it's mainly used for IP addresses (many short items), + * where we gain very little (or compression even gets counter-productive mainly for IPv6 addresses) + * + * @param packet MDNS packet + * @param index offset in the packet + * @param name name representing FQDN in '.' separated parts + * @param last true if appending the last part (domain, typically "arpa") + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t append_fqdn_dots(uint8_t *packet, uint16_t *index, const char *name, bool last) +{ + int len = strlen(name); + char *host = (char *)name; + char *end = host; + char *start = host; + do { + end = memchr(start, '.', len); + end = end ? end : host + len; + int part_len = end - start; + if (!append_single_str(packet, index, start, part_len)) { + return 0; + } + start = ++end; + } while (end < name + len); + + if (!append_single_str(packet, index, "arpa", sizeof("arpa") - 1)) { + return 0; + } + + //empty string so terminate + if (!_mdns_append_u8(packet, index, 0)) { + return 0; + } + return *index; +} +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + /** * @brief appends FQDN to a packet, incrementing the index and * compressing the output if previous occurrence of the string (or part of it) has been found @@ -1104,21 +1160,18 @@ static uint16_t _mdns_append_aaaa_record(uint8_t *packet, uint16_t *index, const */ static uint16_t _mdns_append_question(uint8_t *packet, uint16_t *index, mdns_out_question_t *q) { - const char *str[6]; - uint8_t str_index = 0; uint8_t part_length; - char *host_dup = NULL; // need to duplicate host-name for some cases +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES if (q->host && strstr(q->host, "in-addr")) { - host_dup = strdup(q->host); - char *rest = NULL; - for (char *p = strtok_r(host_dup, ".", &rest); p != NULL; p = strtok_r(NULL, ".", &rest)) { - str[str_index++] = p; + part_length = append_fqdn_dots(packet, index, q->host, false); + if (!part_length) { + return 0; } - if (q->domain) { - str[str_index++] = q->domain; - } - - } else { + } else +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + { + const char *str[4]; + uint8_t str_index = 0; if (q->host) { str[str_index++] = q->host; } @@ -1131,19 +1184,14 @@ static uint16_t _mdns_append_question(uint8_t *packet, uint16_t *index, mdns_out if (q->domain) { str[str_index++] = q->domain; } - - } - - - part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE); - if (!part_length) { - free(host_dup); - return 0; + part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } } part_length += _mdns_append_u16(packet, index, q->type); part_length += _mdns_append_u16(packet, index, q->unicast ? 0x8001 : 0x0001); - free(host_dup); return part_length; } @@ -1221,62 +1269,36 @@ static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_h return num_records; } -static uint16_t _mdns_append_rev_ptr_record(uint8_t *packet, uint16_t *index, const char *name, bool flush, bool bye) +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +/** + * @brief Appends reverse lookup PTR record + */ +static uint8_t _mdns_append_reverse_ptr_record(uint8_t *packet, uint16_t *index, const char *name) { - const char *str[6]; - int i = 0; - if (strstr(name, "in-addr") == NULL) { return 0; } - char *host = strdup(name); - char *rest = NULL; - for (char *p = strtok_r(host, ".", &rest); p != NULL; p = strtok_r(NULL, ".", &rest)) { - str[i++] = p; - } - str[i++] = "arpa"; - uint16_t record_length = 0; - uint8_t part_length; - part_length = _mdns_append_fqdn(packet, index, str, i, MDNS_MAX_PACKET_SIZE); - if (!part_length) { + if (!append_fqdn_dots(packet, index, name, false)) { return 0; } - record_length += part_length; - part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, bye ? 0 : MDNS_ANSWER_PTR_TTL); - if (!part_length) { + if (!_mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, 10 /* TTL set to 10s*/ )) { return 0; } - record_length += part_length; - uint16_t data_len_location = *index - 2; - str[0] = _mdns_self_host.hostname; - str[1] = MDNS_DEFAULT_DOMAIN; + uint16_t data_len_location = *index - 2; /* store the position of size (2=16bis) of this record */ + const char *str[2] = { _mdns_self_host.hostname, MDNS_DEFAULT_DOMAIN }; - part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); + int part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } _mdns_set_u16(packet, data_len_location, part_length); - record_length += part_length; - - return record_length; -} - - -static uint8_t _mdns_append_reverse_ptr_record(uint8_t *packet, uint16_t *index, const char *name, bool flush, bool bye) -{ - uint8_t appended_answers = 0; - - if (_mdns_append_rev_ptr_record(packet, index, name, flush, bye) <= 0) { - return appended_answers; - } - appended_answers++; - - return appended_answers; + return 1; /* appending only 1 record */ } +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ /** * @brief Append PTR answers to packet @@ -1316,8 +1338,10 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an if (answer->type == MDNS_TYPE_PTR) { 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")) { - return _mdns_append_reverse_ptr_record(packet, index, answer->host->hostname, answer->flush, answer->bye) > 0; + return _mdns_append_reverse_ptr_record(packet, index, answer->host->hostname) > 0; +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ } else { return _mdns_append_ptr_record(packet, index, answer->custom_instance, answer->custom_service, answer->custom_proto, @@ -1719,15 +1743,6 @@ static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_serv return true; } -static bool _mdns_create_answer_from_reverse_query(mdns_tx_packet_t *packet, const char *hostname, bool send_flush) -{ - mdns_host_item_t *host = mdns_get_host_item(hostname); - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, NULL, host, send_flush, false)) { - return false; - } - return true; -} - static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const char *hostname, bool send_flush) { mdns_host_item_t *host = mdns_get_host_item(hostname); @@ -1812,18 +1827,24 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_ _mdns_free_tx_packet(packet); return; } +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES } else if (q->type == MDNS_TYPE_PTR) { - if (!_mdns_create_answer_from_reverse_query(packet, q->host, send_flush)) { - _mdns_free_tx_packet(packet); + mdns_host_item_t *host = mdns_get_host_item(q->host); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, NULL, host, send_flush, false)) { return; } +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, NULL, send_flush, false)) { _mdns_free_tx_packet(packet); return; } if (parsed_packet->src_port != MDNS_SERVICE_PORT && // Repeat the queries only for "One-Shot mDNS queries" - (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA || q->type == MDNS_TYPE_PTR)) { + (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + || q->type == MDNS_TYPE_PTR +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + )) { mdns_out_question_t *out_question = malloc(sizeof(mdns_out_question_t)); if (out_question == NULL) { HOOK_MALLOC_FAILED; @@ -3042,7 +3063,11 @@ static bool _mdns_name_is_discovery(mdns_name_t *name, uint16_t type) static bool _mdns_name_is_ours(mdns_name_t *name) { //domain have to be "local" - if (_str_null_or_empty(name->domain) || ( strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN) && strcasecmp(name->domain, "arpa")) ) { + if (_str_null_or_empty(name->domain) || ( strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN) +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + && strcasecmp(name->domain, "arpa") +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + ) ) { return false; } @@ -3967,6 +3992,22 @@ static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action) if (action & MDNS_EVENT_ANNOUNCE_IP6) { _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V6, NULL, 0, true); } + +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + if (action & MDNS_EVENT_IP4_REVERSE_LOOKUP) { + esp_netif_ip_info_t if_ip_info; + if (esp_netif_get_ip_info(_mdns_get_esp_netif(mdns_if), &if_ip_info) == ESP_OK) { + esp_ip4_addr_t *ip = &if_ip_info.ip; + char *reverse_query_name = NULL; + if (asprintf(&reverse_query_name, "%d.%d.%d.%d.in-addr", + esp_ip4_addr4_16(ip), esp_ip4_addr3_16(ip), + esp_ip4_addr2_16(ip), esp_ip4_addr1_16(ip)) > 0 && reverse_query_name) { + ESP_LOGD(TAG, "Registered reverse query: %s.arpa", reverse_query_name); + _mdns_delegate_hostname_add(reverse_query_name, NULL); + } + } + } +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ } /** diff --git a/components/mdns/tests/host_test/components/esp_event/CMakeLists.txt b/components/mdns/tests/host_test/components/esp_event/CMakeLists.txt index f7bfde341..2fd6198bd 100644 --- a/components/mdns/tests/host_test/components/esp_event/CMakeLists.txt +++ b/components/mdns/tests/host_test/components/esp_event/CMakeLists.txt @@ -1,3 +1,2 @@ idf_component_register(SRCS esp_event_mock.c - INCLUDE_DIRS include - REQUIRES) + INCLUDE_DIRS include) diff --git a/components/mdns/tests/host_test/components/esp_event/include/esp_event.h b/components/mdns/tests/host_test/components/esp_event/include/esp_event.h index bc408c7fb..0b8b69ee8 100644 --- a/components/mdns/tests/host_test/components/esp_event/include/esp_event.h +++ b/components/mdns/tests/host_test/components/esp_event/include/esp_event.h @@ -8,12 +8,7 @@ #include "stdbool.h" #include "esp_err.h" #include "esp_event_base.h" -//#include "bsd_strings.h" - - - -//const char *WIFI_EVENT; -//const char *IP_EVENT; +#include "bsd/string.h" esp_err_t esp_event_handler_register(const char *event_base, int32_t event_id, void *event_handler, void *event_handler_arg); diff --git a/components/mdns/tests/host_test/components/freertos/CMakeLists.txt b/components/mdns/tests/host_test/components/freertos/CMakeLists.txt index 925b08732..9180dbce1 100644 --- a/components/mdns/tests/host_test/components/freertos/CMakeLists.txt +++ b/components/mdns/tests/host_test/components/freertos/CMakeLists.txt @@ -1,6 +1,5 @@ idf_component_register(SRCS freertos_linux.c queue_unique_ptr.cpp - INCLUDE_DIRS include - REQUIRES) + INCLUDE_DIRS include) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/components/mdns/tests/host_test/components/freertos/freertos_linux.c b/components/mdns/tests/host_test/components/freertos/freertos_linux.c index d69dea54f..fcba4416e 100644 --- a/components/mdns/tests/host_test/components/freertos/freertos_linux.c +++ b/components/mdns/tests/host_test/components/freertos/freertos_linux.c @@ -158,16 +158,6 @@ void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint } } -//uint32_t esp_get_free_heap_size(void) -//{ -// return 0; -//} -// -//uint32_t esp_random(void) -//{ -// return rand(); -//} - void xTaskNotifyGive(TaskHandle_t task) { diff --git a/components/mdns/tests/host_test/main/main.c b/components/mdns/tests/host_test/main/main.c index 47de777f9..5b3930743 100644 --- a/components/mdns/tests/host_test/main/main.c +++ b/components/mdns/tests/host_test/main/main.c @@ -39,31 +39,26 @@ int main(int argc, char *argv[]) esp_netif_config_t cfg = { .base = &base_cg }; esp_netif_t *sta = esp_netif_new(&cfg); ESP_ERROR_CHECK(mdns_init()); - ESP_ERROR_CHECK(mdns_register_netif(sta)); - ESP_ERROR_CHECK(mdns_netif_action(sta, MDNS_EVENT_ENABLE_IP4)); - - mdns_hostname_set(CONFIG_TEST_HOSTNAME); + ESP_ERROR_CHECK(mdns_hostname_set(CONFIG_TEST_HOSTNAME)); ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_TEST_HOSTNAME); - mdns_ip_addr_t addr4 = { .addr.u_addr.ip4.addr = 0x1020304 }; - addr4.addr.type = ESP_IPADDR_TYPE_V4; - const char *delegated_hostname = "200.0.168.192.in-addr"; - addr4.addr.type = ESP_IPADDR_TYPE_V4; - ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) ); + ESP_ERROR_CHECK(mdns_register_netif(sta)); + ESP_ERROR_CHECK(mdns_netif_action(sta, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_IP4_REVERSE_LOOKUP)); +#ifdef REGISTER_SERVICE //set default mDNS instance name - //mdns_instance_name_set("myesp-inst"); + mdns_instance_name_set("myesp-inst"); //structure with TXT records -// mdns_txt_item_t serviceTxtData[3] = { -// {"board", "esp32"}, -// {"u", "user"}, -// {"p", "password"} -// }; -// vTaskDelay(pdMS_TO_TICKS(1000)); + mdns_txt_item_t serviceTxtData[3] = { + {"board", "esp32"}, + {"u", "user"}, + {"p", "password"} + }; + vTaskDelay(pdMS_TO_TICKS(10000)); + ESP_ERROR_CHECK(mdns_service_add("myesp-service2", "_http", "_tcp", 80, serviceTxtData, 3)); +#endif vTaskDelay(pdMS_TO_TICKS(10000)); - // ESP_ERROR_CHECK(mdns_service_add("myesp-service2", "_http", "_tcp", 80, serviceTxtData, 3)); - // vTaskDelay(2000); query_mdns_host("david-work"); - vTaskDelay(2000); + vTaskDelay(pdMS_TO_TICKS(1000)); esp_netif_destroy(sta); mdns_free(); ESP_LOGI(TAG, "Exit"); diff --git a/components/mdns/tests/host_test/make_eth2_netif b/components/mdns/tests/host_test/make_eth2_netif deleted file mode 100755 index 2436125b7..000000000 --- a/components/mdns/tests/host_test/make_eth2_netif +++ /dev/null @@ -1,5 +0,0 @@ -sudo ip link add eth2 type dummy -sudo ip addr add 192.168.1.200/24 dev eth2 -sudo ip addr add 192.168.1.201/24 dev eth2 -sudo ip link set eth2 up -sudo ifconfig eth2 multicast diff --git a/components/mdns/tests/host_test/sdkconfig.defaults b/components/mdns/tests/host_test/sdkconfig.defaults index 7c7663f3f..621659fac 100644 --- a/components/mdns/tests/host_test/sdkconfig.defaults +++ b/components/mdns/tests/host_test/sdkconfig.defaults @@ -3,5 +3,7 @@ CONFIG_MDNS_NETWORKING_SOCKET=y CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES=y CONFIG_TEST_NETIF_NAME="eth0" CONFIG_TEST_HOSTNAME="myesp" -# CONFIG_MDNS_PREDEF_NETIF_STA is not set -# CONFIG_MDNS_PREDEF_NETIF_AP is not set +CONFIG_MDNS_PREDEF_NETIF_STA=n +CONFIG_MDNS_PREDEF_NETIF_AP=n +CONFIG_MDNS_ENABLE_DEBUG_PRINTS=y +CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y