diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 4dfbd896..2d74a31b 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -93,7 +93,7 @@ static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT; static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT; #endif -#define MDNS_TTL 255 +#define MDNS_IP_TTL 255 static u8_t mdns_netif_client_id; @@ -558,6 +558,7 @@ mdns_handle_question(struct mdns_packet *pkt) struct mdns_answer ans; u8_t rev_v6; int match; + u32_t rr_ttl = MDNS_TTL_120; res = mdns_read_answer(pkt, &ans); if (res != ERR_OK) { @@ -577,7 +578,7 @@ mdns_handle_question(struct mdns_packet *pkt) rev_v6 = 0; match = reply.host_replies & check_host(pkt->netif, &ans.info, &rev_v6); - if (match && (ans.ttl > (mdns->dns_ttl / 2))) { + if (match && (ans.ttl > (rr_ttl / 2))) { /* The RR in the known answer matches an RR we are planning to send, * and the TTL is less than half gone. * If the payload matches we should not send that answer. @@ -631,7 +632,10 @@ mdns_handle_question(struct mdns_packet *pkt) continue; } match = reply.serv_replies[i] & check_service(service, &ans.info); - if (match && (ans.ttl > (service->dns_ttl / 2))) { + if (match & REPLY_SERVICE_TYPE_PTR) { + rr_ttl = MDNS_TTL_4500; + } + if (match && (ans.ttl > (rr_ttl / 2))) { /* The RR in the known answer matches an RR we are planning to send, * and the TTL is less than half gone. * If the payload matches we should not send that answer. @@ -986,11 +990,10 @@ mdns_probe(void* arg) * @param hostname Name to use. Queries for <hostname>.local will be answered * with the IP addresses of the netif. The hostname will be copied, the * given pointer can be on the stack. - * @param dns_ttl Validity time in seconds to send out for IP address data in DNS replies * @return ERR_OK if netif was added, an err_t otherwise */ err_t -mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) +mdns_resp_add_netif(struct netif *netif, const char *hostname) { err_t res; struct mdns_host *mdns; @@ -1006,7 +1009,6 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) netif_set_client_data(netif, mdns_netif_client_id, mdns); MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname))); - mdns->dns_ttl = dns_ttl; mdns->probes_sent = 0; mdns->probing_state = MDNS_PROBING_NOT_STARTED; @@ -1115,14 +1117,13 @@ mdns_resp_rename_netif(struct netif *netif, const char *hostname) * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP * for others ("_udp") * @param port The port the service listens to - * @param dns_ttl Validity time in seconds to send out for service data in DNS replies * @param txt_fn Callback to get TXT data. Will be called each time a TXT reply is created to * allow dynamic replies. * @param txt_data Userdata pointer for txt_fn * @return service_id if the service was added to the netif, an err_t otherwise */ s8_t -mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_data) +mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_data) { s8_t i; s8_t slot = -1; @@ -1155,7 +1156,6 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service srv->txt_userdata = txt_data; srv->proto = (u16_t)proto; srv->port = port; - srv->dns_ttl = dns_ttl; mdns->services[slot] = srv; @@ -1320,9 +1320,9 @@ mdns_resp_init(void) mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL); #if LWIP_MULTICAST_TX_OPTIONS - udp_set_multicast_ttl(mdns_pcb, MDNS_TTL); + udp_set_multicast_ttl(mdns_pcb, MDNS_IP_TTL); #else - mdns_pcb->ttl = MDNS_TTL; + mdns_pcb->ttl = MDNS_IP_TTL; #endif res = udp_bind(mdns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS); LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */ diff --git a/src/apps/mdns/mdns_out.c b/src/apps/mdns/mdns_out.c index 1de751b1..6df14ab6 100644 --- a/src/apps/mdns/mdns_out.c +++ b/src/apps/mdns/mdns_out.c @@ -254,23 +254,29 @@ static err_t mdns_add_a_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain host; mdns_build_host_domain(&host, netif_mdns_data(msg->netif)); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with A record\n")); return mdns_add_answer(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, msg->cache_flush, - (netif_mdns_data(msg->netif))->dns_ttl, - (const u8_t *) netif_ip4_addr(msg->netif), sizeof(ip4_addr_t), NULL); + ttl, (const u8_t *) netif_ip4_addr(msg->netif), + sizeof(ip4_addr_t), NULL); } /** Write a 4.3.2.1.in-addr.arpa -> hostname.local PTR RR to outpacket */ @@ -278,23 +284,29 @@ static err_t mdns_add_hostv4_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain host, revhost; mdns_build_host_domain(&host, netif_mdns_data(msg->netif)); mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(msg->netif)); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v4 PTR record\n")); - return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, msg->cache_flush, - (netif_mdns_data(msg->netif))->dns_ttl, NULL, 0, &host); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + msg->cache_flush, ttl, NULL, 0, &host); } #endif @@ -304,23 +316,29 @@ static err_t mdns_add_aaaa_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, int addrindex) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain host; mdns_build_host_domain(&host, netif_mdns_data(msg->netif)); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with AAAA record\n")); return mdns_add_answer(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, msg->cache_flush, - (netif_mdns_data(msg->netif))->dns_ttl, - (const u8_t *) netif_ip6_addr(msg->netif, addrindex), sizeof(ip6_addr_p_t), NULL); + ttl, (const u8_t *) netif_ip6_addr(msg->netif, addrindex), + sizeof(ip6_addr_p_t), NULL); } /** Write a x.y.z.ip6.arpa -> hostname.local PTR RR to outpacket */ @@ -328,23 +346,29 @@ static err_t mdns_add_hostv6_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, int addrindex) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain host, revhost; mdns_build_host_domain(&host, netif_mdns_data(msg->netif)); mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(msg->netif, addrindex)); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v6 PTR record\n")); - return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, msg->cache_flush, - (netif_mdns_data(msg->netif))->dns_ttl, NULL, 0, &host); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, + msg->cache_flush, ttl, NULL, 0, &host); } #endif @@ -354,23 +378,29 @@ mdns_add_servicetype_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg struct mdns_service *service) { err_t res; + u32_t ttl = MDNS_TTL_4500; struct mdns_domain service_type, service_dnssd; mdns_build_service_domain(&service_type, service, 0); mdns_build_dnssd_domain(&service_dnssd); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service type PTR record\n")); return mdns_add_answer(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, - 0, service->dns_ttl, NULL, 0, &service_type); + 0, ttl, NULL, 0, &service_type); } /** Write a servicetype -> servicename PTR RR to outpacket */ @@ -379,23 +409,29 @@ mdns_add_servicename_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg struct mdns_service *service) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain service_type, service_instance; mdns_build_service_domain(&service_type, service, 0); mdns_build_service_domain(&service_instance, service, 1); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service name PTR record\n")); return mdns_add_answer(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, - 0, service->dns_ttl, NULL, 0, &service_instance); + 0, ttl, NULL, 0, &service_instance); } /** Write a SRV RR to outpacket */ @@ -404,6 +440,7 @@ mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, struct mdns_host *mdns, struct mdns_service *service) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain service_instance, srvhost; u16_t srvdata[3]; mdns_build_service_domain(&service_instance, service, 1); @@ -414,9 +451,10 @@ mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, * name compression MUST NOT be performed on SRV records. */ srvhost.skip_compression = 1; - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl. + * Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ if(reply->questions < 1) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, 0); @@ -425,13 +463,15 @@ mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, } reply->questions = 1; } + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } srvdata[0] = lwip_htons(SRV_PRIORITY); srvdata[1] = lwip_htons(SRV_WEIGHT); srvdata[2] = lwip_htons(service->port); LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with SRV record\n")); return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, - msg->cache_flush, service->dns_ttl, + msg->cache_flush, ttl, (const u8_t *) &srvdata, sizeof(srvdata), &srvhost); } @@ -441,24 +481,30 @@ mdns_add_txt_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg, struct mdns_service *service) { err_t res; + u32_t ttl = MDNS_TTL_120; struct mdns_domain service_instance; mdns_build_service_domain(&service_instance, service, 1); mdns_prepare_txtdata(service); - /* When answering to a legacy querier, we need to repeat the question. - * But this only needs to be done for the question asked (max one question), - * not for the additional records. */ - if(msg->legacy_query && reply->questions < 1) { - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); - res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, 0); - if (res != ERR_OK) { - return res; + /* When answering to a legacy querier, we need to repeat the question and + * limit the ttl to the short legacy ttl */ + if(msg->legacy_query) { + /* Repeating the question only needs to be done for the question asked + * (max one question), not for the additional records. */ + if(reply->questions < 1) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n")); + res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, 0); + if (res != ERR_OK) { + return res; + } + reply->questions = 1; } - reply->questions = 1; + /* ttl of legacy answer may not be greater then 10 seconds */ + ttl = MDNS_TTL_10; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with TXT record\n")); return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, - msg->cache_flush, service->dns_ttl, - (u8_t *) &service->txtdata.name, service->txtdata.length, NULL); + msg->cache_flush, ttl, (u8_t *) &service->txtdata.name, + service->txtdata.length, NULL); } diff --git a/src/include/lwip/apps/mdns.h b/src/include/lwip/apps/mdns.h index bd98d15d..7550ff10 100644 --- a/src/include/lwip/apps/mdns.h +++ b/src/include/lwip/apps/mdns.h @@ -73,11 +73,11 @@ void mdns_resp_init(void); void mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb); -err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); +err_t mdns_resp_add_netif(struct netif *netif, const char *hostname); err_t mdns_resp_remove_netif(struct netif *netif); err_t mdns_resp_rename_netif(struct netif *netif, const char *hostname); -s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); +s8_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_userdata); err_t mdns_resp_del_service(struct netif *netif, s8_t slot); err_t mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name); diff --git a/src/include/lwip/apps/mdns_priv.h b/src/include/lwip/apps/mdns_priv.h index f8692007..981fe5a2 100644 --- a/src/include/lwip/apps/mdns_priv.h +++ b/src/include/lwip/apps/mdns_priv.h @@ -54,6 +54,15 @@ extern "C" { #define SRV_PRIORITY 0 #define SRV_WEIGHT 0 +/* mDNS TTL: (RFC6762 section 10) + * - 120 seconds if the hostname appears somewhere in the RR + * - 75 minutes if not (4500 seconds) + * - 10 seconds if responding to a legacy query + */ +#define MDNS_TTL_10 10 +#define MDNS_TTL_120 120 +#define MDNS_TTL_4500 4500 + /* Domain structs - also visible for unit tests */ struct mdns_domain { @@ -77,8 +86,6 @@ struct mdns_service { * to update txtdata buffer */ service_get_txt_fn_t txt_fn; void *txt_userdata; - /** TTL in seconds of SRV/TXT replies */ - u32_t dns_ttl; /** Protocol, TCP or UDP */ u16_t proto; /** Port of the service */ @@ -91,8 +98,6 @@ struct mdns_host { char name[MDNS_LABEL_MAXLEN + 1]; /** Pointer to services */ struct mdns_service *services[MDNS_MAX_SERVICES]; - /** TTL in seconds of A/AAAA/PTR replies */ - u32_t dns_ttl; /** Number of probes sent for the current name */ u8_t probes_sent; /** State in probing sequence */