diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index c6650ef8dc..ec2770f5d3 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -104,6 +104,12 @@ test_mdns_fuzzer_on_host: variables: FUZZER_TEST_DIR: components/mdns/test_afl_fuzz_host +test_mdns_no_serv_fuzzer_on_host: + extends: .host_fuzzer_test_template + variables: + FUZZER_TEST_DIR: components/mdns/test_afl_fuzz_host + FUZZER_PARAMS: MDNS_NO_SERVICES=on + test_lwip_dns_fuzzer_on_host: extends: .host_fuzzer_test_template variables: diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 67fa442e78..44df1db970 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -158,6 +158,9 @@ static char * _mdns_mangle_name(char* in) { static bool _mdns_service_match(const mdns_service_t * srv, const char * service, const char * proto, const char * hostname) { + if (!service || !proto) { + return false; + } return !strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); } @@ -289,6 +292,12 @@ static bool _mdns_instance_name_match(const char *lhs, const char *rhs) static bool _mdns_service_match_instance(const mdns_service_t *srv, const char *instance, const char *service, const char *proto, const char *hostname) { + // service and proto must be supplied, if not this instance won't match + if (!service || !proto) { + return false; + } + // instance==NULL -> _mdns_instance_name_match() will check the default instance + // hostname==NULL -> matches if instance, service and proto matches return !strcasecmp(srv->service, service) && _mdns_instance_name_match(srv->instance, instance) && !strcasecmp(srv->proto, proto) && (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); } @@ -323,10 +332,11 @@ static mdns_srv_item_t *_mdns_get_service_item_instance(const char *instance, co * * @return the address after the parsed FQDN in the packet or NULL on error */ -static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * start, mdns_name_t * name, char * buf) +static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * start, mdns_name_t * name, char * buf, size_t packet_len) { size_t index = 0; - while (start[index]) { + const uint8_t * packet_end = packet + packet_len; + while (start + index < packet_end && start[index]) { if (name->parts == 4) { name->invalid = true; } @@ -338,6 +348,9 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s } uint8_t i; for (i=0; i= packet_end) { + return NULL; + } buf[i] = start[index++]; } buf[len] = '\0'; @@ -360,7 +373,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s //reference address can not be after where we are return NULL; } - if (_mdns_read_fqdn(packet, packet + address, name, buf)) { + if (_mdns_read_fqdn(packet, packet + address, name, buf, packet_len)) { return start + index; } return NULL; @@ -560,7 +573,7 @@ static inline int append_one_txt_record_entry(uint8_t * packet, uint16_t * index * * @return length of added data: 0 on error or length on success */ -static uint16_t _mdns_append_fqdn(uint8_t * packet, uint16_t * index, const char * strings[], uint8_t count) +static uint16_t _mdns_append_fqdn(uint8_t * packet, uint16_t * index, const char * strings[], uint8_t count, size_t packet_len) { if (!count) { //empty string so terminate @@ -587,7 +600,7 @@ search_next: name.service[0] = 0; name.proto[0] = 0; name.domain[0] = 0; - const uint8_t * content = _mdns_read_fqdn(packet, len_location, &name, buf); + const uint8_t * content = _mdns_read_fqdn(packet, len_location, &name, buf, packet_len); if (!content) { //not a readable fqdn? return 0; @@ -613,7 +626,7 @@ search_next: return 0; } //run the same for the other strings in the name - return written + _mdns_append_fqdn(packet, index, &strings[1], count - 1); + return written + _mdns_append_fqdn(packet, index, &strings[1], count - 1, packet_len); } //we have found the string so let's insert a pointer to it instead @@ -647,7 +660,7 @@ static uint16_t _mdns_append_ptr_record(uint8_t * packet, uint16_t * index, cons str[2] = proto; str[3] = MDNS_DEFAULT_DOMAIN; - part_length = _mdns_append_fqdn(packet, index, str + 1, 3); + part_length = _mdns_append_fqdn(packet, index, str + 1, 3, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -660,7 +673,7 @@ static uint16_t _mdns_append_ptr_record(uint8_t * packet, uint16_t * index, cons record_length += part_length; uint16_t data_len_location = *index - 2; - part_length = _mdns_append_fqdn(packet, index, str, 4); + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -695,7 +708,7 @@ static uint16_t _mdns_append_subtype_ptr_record(uint8_t *packet, uint16_t *index return 0; } - part_length = _mdns_append_fqdn(packet, index, subtype_str, ARRAY_SIZE(subtype_str)); + part_length = _mdns_append_fqdn(packet, index, subtype_str, ARRAY_SIZE(subtype_str), MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -708,7 +721,7 @@ static uint16_t _mdns_append_subtype_ptr_record(uint8_t *packet, uint16_t *index record_length += part_length; uint16_t data_len_location = *index - 2; - part_length = _mdns_append_fqdn(packet, index, instance_str, ARRAY_SIZE(instance_str)); + part_length = _mdns_append_fqdn(packet, index, instance_str, ARRAY_SIZE(instance_str), MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -747,7 +760,7 @@ static uint16_t _mdns_append_sdptr_record(uint8_t * packet, uint16_t * index, md str[1] = service->proto; str[2] = MDNS_DEFAULT_DOMAIN; - part_length = _mdns_append_fqdn(packet, index, sd_str, 4); + part_length = _mdns_append_fqdn(packet, index, sd_str, 4, MDNS_MAX_PACKET_SIZE); record_length += part_length; @@ -758,7 +771,7 @@ static uint16_t _mdns_append_sdptr_record(uint8_t * packet, uint16_t * index, md record_length += part_length; uint16_t data_len_location = *index - 2; - part_length = _mdns_append_fqdn(packet, index, str, 3); + part_length = _mdns_append_fqdn(packet, index, str, 3, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -796,7 +809,7 @@ static uint16_t _mdns_append_txt_record(uint8_t * packet, uint16_t * index, mdns return 0; } - part_length = _mdns_append_fqdn(packet, index, str, 4); + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -860,7 +873,7 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns return 0; } - part_length = _mdns_append_fqdn(packet, index, str, 4); + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -893,7 +906,7 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns return 0; } - part_length = _mdns_append_fqdn(packet, index, str, 2); + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -926,7 +939,7 @@ static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, const return 0; } - part_length = _mdns_append_fqdn(packet, index, str, 2); + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -978,7 +991,7 @@ static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, con } - part_length = _mdns_append_fqdn(packet, index, str, 2); + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -1026,7 +1039,7 @@ static uint16_t _mdns_append_question(uint8_t * packet, uint16_t * index, mdns_o str[str_index++] = q->domain; } - part_length = _mdns_append_fqdn(packet, index, str, str_index); + part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE); if (!part_length) { return 0; } @@ -1610,7 +1623,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_ shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe; if (q->type == MDNS_TYPE_SRV || q->type == MDNS_TYPE_TXT) { mdns_srv_item_t *service = _mdns_get_service_item_instance(q->host, q->service, q->proto, NULL); - if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { + if (service == NULL || !_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { _mdns_free_tx_packet(packet); return; } @@ -2729,10 +2742,17 @@ static bool _hostname_is_ours(const char * hostname) return false; } +/** + * @brief Adds a delegated hostname to the linked list + * @param hostname Host name pointer + * @param address_list Address list + * @return true on success + * false if the host wasn't attached (this is our hostname, or alloc failure) so we have to free the structs + */ static bool _mdns_delegate_hostname_add(const char * hostname, mdns_ip_addr_t * address_list) { if (_hostname_is_ours(hostname)) { - return true; + return false; } mdns_host_item_t * host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t)); @@ -2780,6 +2800,18 @@ static mdns_ip_addr_t * copy_address_list(const mdns_ip_addr_t * address_list) return head; } +static void free_delegated_hostnames(void) +{ + mdns_host_item_t * host = _mdns_host_list; + while (host != NULL) { + free_address_list(host->address_list); + free((char *)host->hostname); + mdns_host_item_t *item = host; + host = host->next; + free(item); + } +} + static bool _mdns_delegate_hostname_remove(const char * hostname) { mdns_srv_item_t * srv = _mdns_server->services; @@ -2930,7 +2962,7 @@ static inline uint32_t _mdns_read_u32(const uint8_t * packet, uint16_t index) * * @return the address after the parsed FQDN in the packet or NULL on error */ -static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * start, mdns_name_t * name) +static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * start, mdns_name_t * name, size_t packet_len) { name->parts = 0; name->sub = 0; @@ -2942,7 +2974,7 @@ static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * static char buf[MDNS_NAME_BUF_LEN]; - const uint8_t * next_data = (uint8_t*)_mdns_read_fqdn(packet, start, name, buf); + const uint8_t * next_data = (uint8_t*)_mdns_read_fqdn(packet, start, name, buf, packet_len); if (!next_data) { return 0; } @@ -3205,6 +3237,28 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) mdns_debug_packet(data, len); #endif + // Check if the packet wasn't sent by us + if (packet->ip_protocol == MDNS_IP_PROTOCOL_V4) { + esp_netif_ip_info_t if_ip_info; + if (esp_netif_get_ip_info(_mdns_get_esp_netif(packet->tcpip_if), &if_ip_info) == ESP_OK && + memcmp(&if_ip_info.ip.addr, &packet->src.u_addr.ip4.addr, sizeof(esp_ip4_addr_t)) == 0) { + return; + } +#if CONFIG_LWIP_IPV6 + } else { + struct esp_ip6_addr if_ip6; + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(packet->tcpip_if), &if_ip6) == ESP_OK && + memcmp(&if_ip6, &packet->src.u_addr.ip6, sizeof(esp_ip6_addr_t)) == 0) { + return; + } +#endif + } + + // Check for the minimum size of mdns packet + if (len <= MDNS_HEAD_ADDITIONAL_OFFSET) { + return; + } + mdns_parsed_packet_t * parsed_packet = (mdns_parsed_packet_t *)malloc(sizeof(mdns_parsed_packet_t)); if (!parsed_packet) { HOOK_MALLOC_FAILED; @@ -3246,7 +3300,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) uint8_t qs = header.questions; while (qs--) { - content = _mdns_parse_fqdn(data, content, name); + content = _mdns_parse_fqdn(data, content, name, len); if (!content) { header.answers = 0; header.additional = 0; @@ -3254,6 +3308,9 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) goto clear_rx_packet;//error } + if (content + MDNS_CLASS_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); bool unicast = !!(mdns_class & 0x8000); @@ -3325,11 +3382,14 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) while (content < (data + len)) { - content = _mdns_parse_fqdn(data, content, name); + content = _mdns_parse_fqdn(data, content, name, len); if (!content) { goto clear_rx_packet;//error } + if (content + MDNS_LEN_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); uint32_t ttl = _mdns_read_u32(content, MDNS_TTL_OFFSET); @@ -3375,15 +3435,14 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } if (type == MDNS_TYPE_PTR) { - if (!_mdns_parse_fqdn(data, data_ptr, name)) { + if (!_mdns_parse_fqdn(data, data_ptr, name, len)) { continue;//error } if (search_result) { _mdns_search_result_add_ptr(search_result, name->host, name->service, name->proto, packet->tcpip_if, packet->ip_protocol, ttl); } else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) { - if (discovery) { - service = _mdns_get_service_item(name->service, name->proto, NULL); + if (discovery && (service = _mdns_get_service_item(name->service, name->proto, NULL))) { _mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service); } else if (service && parsed_packet->questions && !parsed_packet->probe) { _mdns_remove_parsed_question(parsed_packet, type, service); @@ -3415,9 +3474,12 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } } - if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name)) { + if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name, len)) { continue;//error } + if (data_ptr + MDNS_SRV_PORT_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } uint16_t priority = _mdns_read_u16(data_ptr, MDNS_SRV_PRIORITY_OFFSET); uint16_t weight = _mdns_read_u16(data_ptr, MDNS_SRV_WEIGHT_OFFSET); uint16_t port = _mdns_read_u16(data_ptr, MDNS_SRV_PORT_OFFSET); @@ -4649,8 +4711,11 @@ static void _mdns_execute_action(mdns_action_t * action) _mdns_packet_free(action->data.rx_handle.packet); break; case ACTION_DELEGATE_HOSTNAME_ADD: - _mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, - action->data.delegate_hostname.address_list); + if (!_mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, + action->data.delegate_hostname.address_list)) { + free((char *)action->data.delegate_hostname.hostname); + free_address_list(action->data.delegate_hostname.address_list); + } break; case ACTION_DELEGATE_HOSTNAME_REMOVE: _mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname); @@ -5000,6 +5065,7 @@ void mdns_free(void) #endif mdns_service_remove_all(); + free_delegated_hostnames(); _mdns_service_task_stop(); for (i=0; i= data + len) { header.answers = 0; header.additional = 0; header.servers = 0; @@ -5872,7 +5938,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) while (content < (data + len)) { - content = _mdns_parse_fqdn(data, content, name); + content = _mdns_parse_fqdn(data, content, name, len); if (!content) { _mdns_dbg_printf("ERROR: parse mdns records\n"); break; @@ -5940,13 +6006,13 @@ void mdns_debug_packet(const uint8_t * data, size_t len) _mdns_dbg_printf("%u ", ttl); _mdns_dbg_printf("[%u] ", data_len); if (type == MDNS_TYPE_PTR) { - if (!_mdns_parse_fqdn(data, data_ptr, name)) { + if (!_mdns_parse_fqdn(data, data_ptr, name, len)) { _mdns_dbg_printf("ERROR: parse PTR\n"); continue; } _mdns_dbg_printf("%s.%s.%s.%s.\n", name->host, name->service, name->proto, name->domain); } else if (type == MDNS_TYPE_SRV) { - if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name)) { + if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name, len)) { _mdns_dbg_printf("ERROR: parse SRV\n"); continue; } @@ -5984,7 +6050,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) _mdns_dbg_printf(IPSTR "\n", IP2STR(&ip)); } else if (type == MDNS_TYPE_NSEC) { const uint8_t * old_ptr = data_ptr; - const uint8_t * new_ptr = _mdns_parse_fqdn(data, data_ptr, name); + const uint8_t * new_ptr = _mdns_parse_fqdn(data, data_ptr, name, len); if (new_ptr) { _mdns_dbg_printf("%s.%s.%s.%s. ", name->host, name->service, name->proto, name->domain); size_t diff = new_ptr - old_ptr; diff --git a/components/mdns/test_afl_fuzz_host/Makefile b/components/mdns/test_afl_fuzz_host/Makefile index 096e122e68..b700bf4f5f 100644 --- a/components/mdns/test_afl_fuzz_host/Makefile +++ b/components/mdns/test_afl_fuzz_host/Makefile @@ -40,6 +40,10 @@ CFLAGS=-g -Wno-unused-value -Wno-missing-declarations -Wno-pointer-bool-conversi MDNS_C_DEPENDENCY_INJECTION=-include mdns_di.h +ifeq ($(MDNS_NO_SERVICES),on) + CFLAGS+=-DMDNS_NO_SERVICES +endif + ifeq ($(INSTR),off) CC=gcc CFLAGS+=-DINSTR_IS_OFF diff --git a/components/mdns/test_afl_fuzz_host/in/file2.bin b/components/mdns/test_afl_fuzz_host/in/file2.bin new file mode 100644 index 0000000000..a7ce859cc0 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/file2.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_4a_txt.bin b/components/mdns/test_afl_fuzz_host/in/minif_4a_txt.bin new file mode 100644 index 0000000000..37f2803506 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_4a_txt.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_aaaa.bin b/components/mdns/test_afl_fuzz_host/in/minif_aaaa.bin new file mode 100644 index 0000000000..6ddb7acc81 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_aaaa.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_any.bin b/components/mdns/test_afl_fuzz_host/in/minif_any.bin new file mode 100644 index 0000000000..99a6d18d83 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_any.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_disc.bin b/components/mdns/test_afl_fuzz_host/in/minif_disc.bin new file mode 100644 index 0000000000..5f3ba62e20 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_disc.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_ptr.bin b/components/mdns/test_afl_fuzz_host/in/minif_ptr.bin new file mode 100644 index 0000000000..67da5edb07 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_ptr.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_query.bin b/components/mdns/test_afl_fuzz_host/in/minif_query.bin new file mode 100644 index 0000000000..d21c0d29e1 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_query.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/minif_query2.bin b/components/mdns/test_afl_fuzz_host/in/minif_query2.bin new file mode 100644 index 0000000000..986118d3c5 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/minif_query2.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/sub_fritz_m.bin b/components/mdns/test_afl_fuzz_host/in/sub_fritz_m.bin new file mode 100644 index 0000000000..68e1d752c9 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/sub_fritz_m.bin differ diff --git a/components/mdns/test_afl_fuzz_host/in/telnet_ptr.bin b/components/mdns/test_afl_fuzz_host/in/telnet_ptr.bin new file mode 100644 index 0000000000..1cd8e85d80 Binary files /dev/null and b/components/mdns/test_afl_fuzz_host/in/telnet_ptr.bin differ diff --git a/components/mdns/test_afl_fuzz_host/test.c b/components/mdns/test_afl_fuzz_host/test.c index e7fe0b20ea..b48d904e3f 100644 --- a/components/mdns/test_afl_fuzz_host/test.c +++ b/components/mdns/test_afl_fuzz_host/test.c @@ -1,16 +1,8 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -36,11 +28,14 @@ mdns_search_once_t * mdns_test_search_init(const char * name, const char * servi esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t * search); void mdns_test_search_free(mdns_search_once_t * search); void mdns_test_init_di(void); +extern mdns_server_t * _mdns_server; // // mdns function wrappers for mdns setup in test mode static int mdns_test_hostname_set(const char * mdns_hostname) { + _mdns_server->interfaces[MDNS_IF_STA].pcbs[MDNS_IP_PROTOCOL_V4].state = PCB_RUNNING; // mark the PCB running to exercise mdns in fully operational mode + _mdns_server->interfaces[MDNS_IF_STA].pcbs[MDNS_IP_PROTOCOL_V6].state = PCB_RUNNING; int ret = mdns_hostname_set(mdns_hostname); mdns_action_t * a = NULL; GetLastItem(&a); @@ -48,6 +43,18 @@ static int mdns_test_hostname_set(const char * mdns_hostname) return ret; } +static int mdns_test_add_delegated_host(const char * mdns_hostname) +{ + mdns_ip_addr_t addr = { .addr = { .u_addr = ESP_IPADDR_TYPE_V4 } }; + addr.addr.u_addr.ip4.addr = 0x11111111; + int ret = mdns_delegate_hostname_add(mdns_hostname, &addr); + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + + static int mdns_test_service_instance_name_set(const char * service, const char * proto, const char * instance) { int ret = mdns_service_instance_name_set(service, proto, instance); @@ -66,6 +73,25 @@ static int mdns_test_service_txt_set(const char * service, const char * proto, return ret; } +static int mdns_test_sub_service_add(const char * sub_name, const char * service_name, const char * proto, uint32_t port) +{ + if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) { + // This is expected failure as the service thread is not running + } + mdns_action_t * a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + + if (mdns_test_mdns_get_service_item(service_name, proto)==NULL) { + return ESP_FAIL; + } + int ret = mdns_service_subtype_add_for_host(NULL, service_name, proto, NULL, sub_name); + a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + static int mdns_test_service_add(const char * service_name, const char * proto, uint32_t port) { if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) { @@ -81,9 +107,9 @@ static int mdns_test_service_add(const char * service_name, const char * proto, return ESP_OK; } -static mdns_result_t* mdns_test_query(const char * service_name, const char * proto) +static mdns_result_t* mdns_test_query(const char * name, const char * service, const char * proto, uint16_t type) { - search = mdns_test_search_init(NULL, service_name, proto, MDNS_TYPE_PTR, 3000, 20); + search = mdns_test_search_init(name, service, proto, type, 3000, 20); if (!search) { abort(); } @@ -142,6 +168,20 @@ int main(int argc, char** argv) abort(); } + if (mdns_test_add_delegated_host(mdns_hostname) || mdns_test_add_delegated_host("megafritz")) { + abort(); + } + +#ifndef MDNS_NO_SERVICES + + if (mdns_test_sub_service_add("_server", "_fritz", "_tcp", 22)) { + abort(); + } + + if (mdns_test_service_add("_telnet", "_tcp", 22)) { + abort(); + } + if (mdns_test_service_add("_workstation", "_tcp", 9)) { abort(); } @@ -186,7 +226,7 @@ int main(int argc, char** argv) { abort(); } - +#endif mdns_result_t * results = NULL; FILE *file; size_t nread; @@ -216,12 +256,22 @@ int main(int argc, char** argv) memset(buf, 0, 1460); size_t len = read(0, buf, 1460); #endif - mypbuf.payload = buf; + mypbuf.payload = malloc(len); + memcpy(mypbuf.payload, buf, len); mypbuf.len = len; g_packet.pb = &mypbuf; - mdns_test_query("_afpovertcp", "_tcp"); + mdns_test_query("minifritz", "_fritz", "_tcp", MDNS_TYPE_ANY); + mdns_test_query(NULL, "_fritz", "_tcp", MDNS_TYPE_PTR); + mdns_test_query(NULL, "_afpovertcp", "_tcp", MDNS_TYPE_PTR); mdns_parse_packet(&g_packet); + free(mypbuf.payload); } +#ifndef MDNS_NO_SERVICES + mdns_service_remove_all(); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); +#endif ForceTaskDelete(); mdns_free(); return 0; diff --git a/examples/protocols/mdns/main/Kconfig.projbuild b/examples/protocols/mdns/main/Kconfig.projbuild index ca2f2bbf34..bc4b1a055c 100644 --- a/examples/protocols/mdns/main/Kconfig.projbuild +++ b/examples/protocols/mdns/main/Kconfig.projbuild @@ -1,5 +1,12 @@ menu "Example Configuration" + config MDNS_GPIO_RANGE_MAX + int + default 33 if IDF_TARGET_ESP32 + default 46 if IDF_TARGET_ESP32S2 + default 19 if IDF_TARGET_ESP32C3 + default 48 if IDF_TARGET_ESP32S3 + config MDNS_HOSTNAME string "mDNS Hostname" default "esp32-mdns" @@ -34,4 +41,11 @@ menu "Example Configuration" If enabled, a portion of MAC address is added to the hostname, this is used for evaluation of tests in CI + config MDNS_BUTTON_GPIO + int "Button GPIO to trigger querries" + range 0 MDNS_GPIO_RANGE_MAX + default 0 + help + Set the GPIO number used as mDNS test button + endmenu diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index 94e9140eaa..0b5e962458 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -22,7 +22,7 @@ #define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE -#define EXAMPLE_BUTTON_GPIO 0 +#define EXAMPLE_BUTTON_GPIO CONFIG_MDNS_BUTTON_GPIO static const char * TAG = "mdns-test"; static char * generate_hostname(void); @@ -174,7 +174,6 @@ static void query_mdns_hosts_async(const char * host_name) ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name); mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1, NULL); - mdns_query_async_delete(s_a); mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1, NULL); while (s_a || s_aaaa) { if (s_a && check_and_print_result(s_a)) { @@ -187,6 +186,7 @@ static void query_mdns_hosts_async(const char * host_name) mdns_query_async_delete(s_aaaa); s_aaaa = NULL; } + vTaskDelay(50 / portTICK_PERIOD_MS); } } diff --git a/examples/protocols/mdns/mdns_example_test.py b/examples/protocols/mdns/mdns_example_test.py index 20e6bad040..f067077182 100644 --- a/examples/protocols/mdns/mdns_example_test.py +++ b/examples/protocols/mdns/mdns_example_test.py @@ -91,6 +91,7 @@ def mdns_server(esp_host): console_log('Received query: {} '.format(dns.__repr__())) sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr) if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A: + console_log('Received answer from {}'.format(dns.an[0].name)) if dns.an[0].name == esp_host + u'.local': console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) esp_answered.set() @@ -113,7 +114,7 @@ def test_examples_protocol_mdns(env, extra_data): 3. check the mdns name is accessible 4. check DUT output if mdns advertized host is resolved """ - dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT) + dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT, app_config_name='eth_kit') # check and log bin size binary_file = os.path.join(dut1.app.binary_path, 'mdns_test.bin') bin_size = os.path.getsize(binary_file) diff --git a/examples/protocols/mdns/sdkconfig.ci b/examples/protocols/mdns/sdkconfig.ci.eth_kit similarity index 89% rename from examples/protocols/mdns/sdkconfig.ci rename to examples/protocols/mdns/sdkconfig.ci.eth_kit index 65d9a2fdc2..703b4543ee 100644 --- a/examples/protocols/mdns/sdkconfig.ci +++ b/examples/protocols/mdns/sdkconfig.ci.eth_kit @@ -1,3 +1,4 @@ +CONFIG_IDF_TARGET="esp32" CONFIG_MDNS_RESOLVE_TEST_SERVICES=y CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y @@ -11,3 +12,4 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index a20c8154c5..27545daf26 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1213,7 +1213,6 @@ components/mdns/test_afl_fuzz_host/esp_netif_mock.c components/mdns/test_afl_fuzz_host/mdns_di.h components/mdns/test_afl_fuzz_host/mdns_mock.h components/mdns/test_afl_fuzz_host/sdkconfig.h -components/mdns/test_afl_fuzz_host/test.c components/mqtt/host_test/main/test_mqtt_client.cpp components/mqtt/host_test/mocks/include/freertos/FreeRTOSConfig.h components/mqtt/host_test/mocks/include/freertos/portmacro.h