From dcbbed9c27b86bbddbfd951eb5b934d11bdf9dca Mon Sep 17 00:00:00 2001 From: Liu Han Date: Wed, 26 Sep 2018 10:55:23 +0800 Subject: [PATCH] feat(mdns): Sync mDNS function from ESP-IDF 607d899503afd4ce0e457c815249a0213083f9f5 --- components/mdns/CMakeLists.txt | 9 + components/mdns/Kconfig | 13 + components/mdns/mdns.c | 63 +++-- components/mdns/mdns_networking.c | 225 ++++++++++-------- .../mdns/private_include/mdns_private.h | 6 +- .../mdns/test_afl_fuzz_host/esp32_compat.h | 1 + 6 files changed, 194 insertions(+), 123 deletions(-) create mode 100644 components/mdns/CMakeLists.txt create mode 100644 components/mdns/Kconfig diff --git a/components/mdns/CMakeLists.txt b/components/mdns/CMakeLists.txt new file mode 100644 index 00000000..0933e300 --- /dev/null +++ b/components/mdns/CMakeLists.txt @@ -0,0 +1,9 @@ +set(COMPONENT_SRCS "mdns.c" + "mdns_console.c" + "mdns_networking.c") +set(COMPONENT_ADD_INCLUDEDIRS "include") +set(COMPONENT_PRIV_INCLUDEDIRS "private_include") +set(COMPONENT_REQUIRES lwip mbedtls console tcpip_adapter) + +register_component() + diff --git a/components/mdns/Kconfig b/components/mdns/Kconfig new file mode 100644 index 00000000..321b0f65 --- /dev/null +++ b/components/mdns/Kconfig @@ -0,0 +1,13 @@ +menu "mDNS" + +config MDNS_MAX_SERVICES + int "Max number of services" + range 1 64 + default 10 + help + Services take up a certain amount of memory, and allowing fewer + services to be open at the same time conserves memory. Specify + the maximum amount of services here. The valid value is from 1 + to 64. + +endmenu diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 0cc5865a..38d67826 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -16,7 +16,6 @@ #include "mdns_private.h" #include "mdns_networking.h" #include -#include #ifdef MDNS_ENABLE_DEBUG void mdns_debug_packet(const uint8_t * data, size_t len); @@ -97,6 +96,21 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char return NULL; } +static bool _mdns_can_add_more_services(void) +{ + mdns_srv_item_t * s = _mdns_server->services; + uint16_t service_num = 0; + while (s) { + service_num ++; + s = s->next; + if (service_num >= MDNS_MAX_SERVICES) { + return false; + } + } + + return true; +} + esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet) { mdns_action_t * action = NULL; @@ -1181,7 +1195,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed } if (service) { if (q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_ANY) { - if (q->type == MDNS_TYPE_PTR) { + if (q->type == MDNS_TYPE_PTR || !parsed_packet->probe) { shared = true; } if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service->service, false, false) @@ -1405,6 +1419,7 @@ static void _mdns_pcb_send_bye(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t i if (!packet) { return; } + packet->flags = MDNS_FLAGS_AUTHORITATIVE; size_t i; for (i=0; ianswers, MDNS_TYPE_PTR, services[i]->service, true, true)) { @@ -1741,6 +1756,17 @@ static mdns_txt_linked_item_t * _mdns_allocate_txt(size_t num_items, mdns_txt_it } return new_txt; } +static void _mdns_free_linked_txt(mdns_txt_linked_item_t *txt) +{ + mdns_txt_linked_item_t *t; + while (txt) { + t = txt; + txt = txt->next; + free((char *)t->value); + free((char *)t->key); + free(t); + } +} /** * @brief creates/allocates new service @@ -2555,7 +2581,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) continue; } - if (type == MDNS_TYPE_ANY) { + if (type == MDNS_TYPE_ANY && !_str_null_or_empty(name->host)) { parsed_packet->probe = true; } @@ -3539,7 +3565,7 @@ static void _mdns_free_action(mdns_action_t * action) free(action->data.srv_instance.instance); break; case ACTION_SERVICE_TXT_REPLACE: - free(action->data.srv_txt_replace.txt); + _mdns_free_linked_txt(action->data.srv_txt_replace.txt); break; case ACTION_SERVICE_TXT_SET: free(action->data.srv_txt_set.key); @@ -3621,14 +3647,8 @@ static void _mdns_execute_action(mdns_action_t * action) service = action->data.srv_txt_replace.service->service; txt = service->txt; service->txt = NULL; - while (txt) { - t = txt; - txt = txt->next; - free((char *)t->value); - free((char *)t->key); - free(t); - } - service->txt = _mdns_allocate_txt(action->data.srv_txt_replace.num_items, action->data.srv_txt_replace.txt); + _mdns_free_linked_txt(txt); + service->txt = action->data.srv_txt_replace.txt; _mdns_announce_all_pcbs(&action->data.srv_txt_replace.service, 1, false); break; @@ -4125,6 +4145,11 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { return ESP_ERR_INVALID_ARG; } + + if (!_mdns_can_add_more_services()) { + return ESP_ERR_NO_MEM; + } + mdns_srv_item_t * item = _mdns_get_service_item(service, proto); if (item) { return ESP_ERR_INVALID_ARG; @@ -4204,27 +4229,25 @@ esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_tx return ESP_ERR_NOT_FOUND; } - mdns_txt_item_t * txt_copy = NULL; + mdns_txt_linked_item_t * new_txt = NULL; if (num_items){ - txt_copy = (mdns_txt_item_t *)malloc(num_items * sizeof(mdns_txt_item_t)); - if (!txt_copy) { + new_txt = _mdns_allocate_txt(num_items, txt); + if (!new_txt) { return ESP_ERR_NO_MEM; } - memcpy(txt_copy, txt, num_items * sizeof(mdns_txt_item_t)); } mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); if (!action) { - free(txt_copy); + _mdns_free_linked_txt(new_txt); return ESP_ERR_NO_MEM; } action->type = ACTION_SERVICE_TXT_REPLACE; action->data.srv_txt_replace.service = s; - action->data.srv_txt_replace.num_items = num_items; - action->data.srv_txt_replace.txt = txt_copy; + action->data.srv_txt_replace.txt = new_txt; if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { - free(txt_copy); + _mdns_free_linked_txt(new_txt); free(action); return ESP_ERR_NO_MEM; } diff --git a/components/mdns/mdns_networking.c b/components/mdns/mdns_networking.c index e4ab816d..4e64e36c 100644 --- a/components/mdns/mdns_networking.c +++ b/components/mdns/mdns_networking.c @@ -14,6 +14,89 @@ extern mdns_server_t * _mdns_server; * */ +static struct udp_pcb * _pcb_main = NULL; + +static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport); + +/** + * @brief Low level UDP PCB Initialize + */ +static esp_err_t _udp_pcb_main_init() +{ + if(_pcb_main) { + return ESP_OK; + } + _pcb_main = udp_new(); + if (!_pcb_main) { + return ESP_ERR_NO_MEM; + } + if (udp_bind(_pcb_main, IP_ANY_TYPE, MDNS_SERVICE_PORT) != 0) { + udp_remove(_pcb_main); + _pcb_main = NULL; + return ESP_ERR_INVALID_STATE; + } + _pcb_main->mcast_ttl = 1; + _pcb_main->remote_port = MDNS_SERVICE_PORT; + ip_addr_copy(_pcb_main->remote_ip, ip_addr_any_type); + udp_recv(_pcb_main, &_udp_recv, _mdns_server); + return ESP_OK; +} + +/** + * @brief Low level UDP PCB Free + */ +static void _udp_pcb_main_deinit() +{ + if(_pcb_main){ + udp_recv(_pcb_main, NULL, NULL); + udp_disconnect(_pcb_main); + udp_remove(_pcb_main); + _pcb_main = NULL; + } +} + +/** + * @brief Low level UDP Multicast membership control + */ +static esp_err_t _udp_join_group(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, bool join) +{ + struct netif * netif = NULL; + void * nif = NULL; + esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif); + if (err) { + return ESP_ERR_INVALID_ARG; + } + netif = (struct netif *)nif; + + if (ip_protocol == MDNS_IP_PROTOCOL_V4) { + ip_addr_t multicast_addr; + IP_ADDR4(&multicast_addr, 224, 0, 0, 251); + + if(join){ + if (igmp_joingroup_netif(netif, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup_netif(netif, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) { + return ESP_ERR_INVALID_STATE; + } + } + } else { + ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000); + + if(join){ + if (mld6_joingroup_netif(netif, &(multicast_addr.u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (mld6_leavegroup_netif(netif, &(multicast_addr.u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } + } + return ESP_OK; +} + /** * @brief the receive callback of the raw udp api. Packets are received here * @@ -82,6 +165,21 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip } +/** + * @brief Check if any of the interfaces is up + */ +static bool _udp_pcb_is_in_use(){ + int i, p; + for (i=0; iinterfaces[i].pcbs[p].pcb){ + return true; + } + } + } + return false; +} + /** * @brief Stop PCB Main code */ @@ -92,122 +190,47 @@ static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_p } mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; if (_pcb->pcb) { - _pcb->state = PCB_OFF; - udp_recv(_pcb->pcb, NULL, NULL); - udp_disconnect(_pcb->pcb); - udp_remove(_pcb->pcb); free(_pcb->probe_services); + _pcb->state = PCB_OFF; _pcb->pcb = NULL; _pcb->probe_ip = false; _pcb->probe_services = NULL; _pcb->probe_services_len = 0; _pcb->probe_running = false; _pcb->failed_probes = 0; + _udp_join_group(tcpip_if, ip_protocol, false); + if(!_udp_pcb_is_in_use()) { + _udp_pcb_main_deinit(); + } } } -/** - * @brief Start PCB V4 - */ -static esp_err_t _udp_pcb_v4_init(tcpip_adapter_if_t tcpip_if) -{ - tcpip_adapter_ip_info_t if_ip_info; - - if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) { - return ESP_ERR_INVALID_STATE; - } - - if (tcpip_adapter_get_ip_info(tcpip_if, &if_ip_info) || if_ip_info.ip.addr == 0) { - return ESP_ERR_INVALID_ARG; - } - - ip_addr_t interface_addr = IPADDR4_INIT(if_ip_info.ip.addr); - - ip_addr_t multicast_addr; - IP_ADDR4(&multicast_addr, 224, 0, 0, 251); - - if (igmp_joingroup((const struct ip4_addr *)&interface_addr.u_addr.ip4, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) { - return ESP_ERR_INVALID_STATE; - } - - struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V4); - if (!pcb) { - return ESP_ERR_NO_MEM; - } - - if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { - udp_remove(pcb); - return ESP_ERR_INVALID_STATE; - } - - pcb->mcast_ttl = 1; - pcb->remote_port = MDNS_SERVICE_PORT; - ip_addr_copy(pcb->multicast_ip, interface_addr); - ip_addr_copy(pcb->remote_ip, multicast_addr); - - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb = pcb; - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].failed_probes = 0; - udp_recv(pcb, &_udp_recv, _mdns_server); - - return ESP_OK; -} - -/** - * @brief Start PCB V6 - */ -static esp_err_t _udp_pcb_v6_init(tcpip_adapter_if_t tcpip_if) -{ - ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000); - ip_addr_t interface_addr; - interface_addr.type = IPADDR_TYPE_V6; - - if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) { - return ESP_ERR_INVALID_STATE; - } - - if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &interface_addr.u_addr.ip6)) { - return ESP_ERR_INVALID_ARG; - } - - if (mld6_joingroup(&(interface_addr.u_addr.ip6), &(multicast_addr.u_addr.ip6))) { - return ESP_ERR_INVALID_STATE; - } - - struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V6); - if (!pcb) { - return ESP_ERR_NO_MEM; - } - - if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) { - udp_remove(pcb); - return ESP_ERR_INVALID_STATE; - } - - pcb->remote_port = MDNS_SERVICE_PORT; - ip_addr_copy(pcb->remote_ip, multicast_addr); - - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb = pcb; - _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].failed_probes = 0; - udp_recv(pcb, &_udp_recv, _mdns_server); - - return ESP_OK; -} - /** * @brief Start PCB Main code */ static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) { - if (ip_protocol == MDNS_IP_PROTOCOL_V4) { - return _udp_pcb_v4_init(tcpip_if); - } else if (ip_protocol == MDNS_IP_PROTOCOL_V6) { - return _udp_pcb_v6_init(tcpip_if); + if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) { + return ESP_ERR_INVALID_STATE; } - return ESP_ERR_INVALID_ARG; + + esp_err_t err = _udp_join_group(tcpip_if, ip_protocol, true); + if(err){ + return err; + } + + err = _udp_pcb_main_init(); + if(err){ + return err; + } + + _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = _pcb_main; + _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0; + return ESP_OK; } typedef struct { - struct tcpip_api_call call; + struct tcpip_api_call_data call; tcpip_adapter_if_t tcpip_if; mdns_ip_protocol_t ip_protocol; esp_err_t err; @@ -216,7 +239,7 @@ typedef struct { /** * @brief Start PCB from LwIP thread */ -static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg) +static err_t _mdns_pcb_init_api(struct tcpip_api_call_data *api_call_msg) { mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol); @@ -226,7 +249,7 @@ static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg) /** * @brief Stop PCB from LwIP thread */ -static err_t _mdns_pcb_deinit_api(struct tcpip_api_call *api_call_msg) +static err_t _mdns_pcb_deinit_api(struct tcpip_api_call_data *api_call_msg) { mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg; _udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol); @@ -245,7 +268,7 @@ esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_prot .tcpip_if = tcpip_if, .ip_protocol = ip_protocol }; - tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call_data*)&msg); return msg.err; } @@ -255,7 +278,7 @@ esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_pr .tcpip_if = tcpip_if, .ip_protocol = ip_protocol }; - tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call_data*)&msg); return msg.err; } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index a3d9fa27..568c81b0 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -20,6 +20,9 @@ #define _mdns_dbg_printf(...) printf(__VA_ARGS__) #endif +/** The maximum number of services */ +#define MDNS_MAX_SERVICES CONFIG_MDNS_MAX_SERVICES + #define MDNS_ANSWER_PTR_TTL 4500 #define MDNS_ANSWER_TXT_TTL 4500 #define MDNS_ANSWER_SRV_TTL 120 @@ -361,8 +364,7 @@ typedef struct { } srv_port; struct { mdns_srv_item_t * service; - uint8_t num_items; - mdns_txt_item_t * txt; + mdns_txt_linked_item_t * txt; } srv_txt_replace; struct { mdns_srv_item_t * service; diff --git a/components/mdns/test_afl_fuzz_host/esp32_compat.h b/components/mdns/test_afl_fuzz_host/esp32_compat.h index 402807c4..7a662607 100644 --- a/components/mdns/test_afl_fuzz_host/esp32_compat.h +++ b/components/mdns/test_afl_fuzz_host/esp32_compat.h @@ -34,6 +34,7 @@ #include #include +#define CONFIG_MDNS_MAX_SERVICES 25 #define ERR_OK 0 #define ESP_OK 0