Compare commits

...

2 commits

Author SHA1 Message Date
Scott Shawcroft
d26459c32c
Use PRIu32 for conflict time 2022-11-23 15:22:39 -08:00
Scott Shawcroft
3fcb0b05fa
Add secondary hostname support 2022-11-23 14:16:50 -08:00
7 changed files with 179 additions and 33 deletions

View file

@ -243,11 +243,14 @@ get_mdns_pcb(void)
* @return Bitmask of which replies to send
*/
static int
check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply)
check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply, u8_t* host_index)
{
err_t res;
int replies = 0;
int i;
struct mdns_domain mydomain;
const char* hostname;
struct mdns_host* mdns;
LWIP_UNUSED_ARG(reverse_v6_reply); /* if ipv6 is disabled */
@ -259,7 +262,6 @@ check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply)
/* Handle PTR for our addresses */
if (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY) {
#if LWIP_IPV6
int i;
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
res = mdns_build_reverse_v6_domain(&mydomain, netif_ip6_addr(netif, i));
@ -283,21 +285,34 @@ check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply)
#endif
}
res = mdns_build_host_domain(&mydomain, NETIF_TO_HOST(netif));
/* Handle requests for our hostname */
if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
/* TODO return NSEC if unsupported protocol requested */
#if LWIP_IPV4
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))
&& (rr->type == DNS_RRTYPE_A || rr->type == DNS_RRTYPE_ANY)) {
replies |= REPLY_HOST_A;
mdns = NETIF_TO_HOST(netif);
for (i = 0; i < MDNS_MAX_SECONDARY_HOSTNAMES + 1; i++) {
hostname = mdns->name;
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
if (i > 0) {
hostname = mdns->secondary_hostnames[i - 1];
}
#endif
res = mdns_build_host_domain(&mydomain, hostname);
/* Handle requests for our hostname */
if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
*host_index = i;
/* TODO return NSEC if unsupported protocol requested */
#if LWIP_IPV4
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))
&& (rr->type == DNS_RRTYPE_A || rr->type == DNS_RRTYPE_ANY)) {
replies |= REPLY_HOST_A;
}
#endif
#if LWIP_IPV6
if (rr->type == DNS_RRTYPE_AAAA || rr->type == DNS_RRTYPE_ANY) {
replies |= REPLY_HOST_AAAA;
}
if (rr->type == DNS_RRTYPE_AAAA || rr->type == DNS_RRTYPE_ANY) {
replies |= REPLY_HOST_AAAA;
}
#endif
break;
}
}
return replies;
@ -1096,7 +1111,7 @@ mdns_parse_pkt_questions(struct netif *netif, struct mdns_packet *pkt,
reply->unicast_reply_requested = 1;
}
reply->host_replies |= check_host(netif, &q.info, &reply->host_reverse_v6_replies);
reply->host_replies |= check_host(netif, &q.info, &reply->host_reverse_v6_replies, &reply->host_index);
for (i = 0; i < MDNS_MAX_SERVICES; i++) {
service = mdns->services[i];
@ -1130,6 +1145,7 @@ mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
while (pkt->answers_left) {
struct mdns_answer ans;
u8_t rev_v6;
u8_t host_index;
int match;
u32_t rr_ttl = MDNS_TTL_120;
@ -1150,7 +1166,8 @@ mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
}
rev_v6 = 0;
match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
match = reply->host_replies & check_host(netif, &ans.info, &rev_v6, &host_index);
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.
@ -1160,8 +1177,16 @@ mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
/* Read domain and compare */
struct mdns_domain known_ans, my_ans;
u16_t len;
const char* hostname;
len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans);
res = mdns_build_host_domain(&my_ans, mdns);
hostname = mdns->name;
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
if (host_index > 0) {
hostname = mdns->secondary_hostnames[host_index];
}
#endif
res = mdns_build_host_domain(&my_ans, hostname);
if (len != MDNS_READNAME_ERROR && res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
#if LWIP_IPV4
if (match & REPLY_HOST_PTR_V4) {
@ -1260,7 +1285,7 @@ mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
read_pos += len;
/* Check host field */
len = mdns_readname(pkt->pbuf, read_pos, &known_ans);
mdns_build_host_domain(&my_ans, mdns);
mdns_build_host_domain(&my_ans, mdns->name);
if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&known_ans, &my_ans)) {
break;
}
@ -1322,7 +1347,7 @@ mdns_parse_pkt_authoritative_answers(struct netif *netif, struct mdns_packet *pk
}
rev_v6 = 0;
match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
match = reply->host_replies & check_host(netif, &ans.info, &rev_v6, &reply->host_index);
if (match) {
reply->probe_query_recv = 1;
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own host info received\n"));
@ -1747,7 +1772,7 @@ mdns_conflict_save_time(struct netif *netif)
/* Print timestamp list */
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: conflict timestamp list, insert index = %d\n", mdns->index));
for(i = 0; i < MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; i++) {
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: time no. %d = %d\n", i, mdns->conflict_time[i]));
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: time no. %d = %" PRIu32 "\n", i, mdns->conflict_time[i]));
}
/* Check if we had enough conflicts, minimum 15 */
if (mdns->num_conflicts >= MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT) {
@ -1929,7 +1954,7 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
struct mdns_domain domain;
u8_t i;
res = mdns_build_host_domain(&domain, mdns);
res = mdns_build_host_domain(&domain, mdns->name);
if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!"));
mdns_probe_conflict(netif, 0);
@ -1966,7 +1991,7 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
u8_t conflict = 0;
/* Evaluate unique hostname records -> A and AAAA */
res = mdns_build_host_domain(&domain, mdns);
res = mdns_build_host_domain(&domain, mdns->name);
if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches host domain, assuming conflict\n"));
/* This means a conflict has taken place, except when the packet contains
@ -2034,7 +2059,7 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
read_pos += len;
/* Check host field */
len = mdns_readname(pkt->pbuf, read_pos, &srv_ans);
mdns_build_host_domain(&my_ans, mdns);
mdns_build_host_domain(&my_ans, mdns->name);
if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&srv_ans, &my_ans)) {
break;
}
@ -2495,6 +2520,87 @@ mdns_resp_netif_active(struct netif *netif)
return NETIF_TO_HOST(netif) != NULL;
}
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
/**
* @ingroup mdns
* Adds an additional secondary hostname.
* @param netif The network interface to test.
* @param hostname Name to use. Queries for &lt;hostname&gt;.local will be answered
* with the IP addresses of the netif. The hostname will be copied, the
* given pointer can be on the stack. The hostname will not be used
* in service answers.
* @return ERR_OK if hostname could be added as secondary on netif, an err_t otherwise
*/
err_t mdns_resp_add_secondary_hostname(struct netif *netif, const char* hostname) {
struct mdns_host *mdns;
size_t len;
u8_t slot;
int i;
LWIP_ASSERT_CORE_LOCKED();
len = strlen(hostname);
LWIP_ERROR("mdns_resp_add_secondary_hostname: netif != NULL", (netif != NULL), return ERR_VAL);
LWIP_ERROR("mdns_resp_add_secondary_hostname: Hostname too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
mdns = NETIF_TO_HOST(netif);
LWIP_ERROR("mdns_resp_add_secondary_hostname: Not an mdns netif", (mdns != NULL), return ERR_VAL);
slot = MDNS_MAX_SECONDARY_HOSTNAMES;
for (i = 0; i < MDNS_MAX_SECONDARY_HOSTNAMES; i++) {
if (strlen(mdns->secondary_hostnames[i]) == 0) {
slot = i;
break;
}
}
LWIP_ERROR("mdns_resp_add_secondary_hostname: Secondary hostname list full (increase MDNS_MAX_SECONDARY_HOSTNAMES)", (slot < MDNS_MAX_SECONDARY_HOSTNAMES), return ERR_MEM);
MEMCPY(&mdns->secondary_hostnames[slot], hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, len));
mdns->secondary_hostnames[slot][len] = '\0'; /* null termination in case new name is shorter than previous */
mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
return ERR_OK;
}
/**
* @ingroup mdns
* Deletes an additional secondary hostname.
* @param netif The network interface to test.
* @param hostname Name to remove. Queries for &lt;hostname&gt;.local will no longer
* be answered with the IP addresses of the netif.
* @return ERR_OK if hostname was removed as secondary on netif, an err_t otherwise
*/
err_t mdns_resp_del_secondary_hostname(struct netif *netif, const char* hostname) {
struct mdns_host *mdns;
size_t len;
u8_t slot;
int i;
LWIP_ASSERT_CORE_LOCKED();
len = strlen(hostname);
LWIP_ERROR("mdns_resp_del_secondary_hostname: netif != NULL", (netif != NULL), return ERR_VAL);
LWIP_ERROR("mdns_resp_del_secondary_hostname: Hostname too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
mdns = NETIF_TO_HOST(netif);
LWIP_ERROR("mdns_resp_del_secondary_hostname: Not an mdns netif", (mdns != NULL), return ERR_VAL);
slot = MDNS_MAX_SECONDARY_HOSTNAMES;
for (i = 0; i < MDNS_MAX_SECONDARY_HOSTNAMES; i++) {
if (strcmp(mdns->secondary_hostnames[i], hostname) == 0) {
slot = i;
break;
}
}
LWIP_ERROR("mdns_resp_del_secondary_hostname: Invalid secondary hostname", slot < MDNS_MAX_SECONDARY_HOSTNAMES, return ERR_VAL);
mdns->secondary_hostnames[slot][0] = '\0';
mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
return ERR_OK;
}
#endif
/**
* @ingroup mdns
* Add a service to the selected network interface.

View file

@ -432,17 +432,17 @@ mdns_add_dotlocal(struct mdns_domain *domain)
/**
* Build the \<hostname\>.local. domain name
* @param domain Where to write the domain name
* @param mdns TMDNS netif descriptor.
* @param hostname Hostname string.
* @return ERR_OK if domain \<hostname\>.local. was written, an err_t otherwise
*/
err_t
mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns)
mdns_build_host_domain(struct mdns_domain *domain, const char *hostname)
{
err_t res;
LWIP_UNUSED_ARG(res);
memset(domain, 0, sizeof(struct mdns_domain));
LWIP_ERROR("mdns_build_host_domain: mdns != NULL", (mdns != NULL), return ERR_VAL);
res = mdns_domain_add_label(domain, mdns->name, (u8_t)strlen(mdns->name));
LWIP_ERROR("mdns_build_host_domain: hostname != NULL", (hostname != NULL), return ERR_VAL);
res = mdns_domain_add_label(domain, hostname, (u8_t)strlen(hostname));
LWIP_ERROR("mdns_build_host_domain: Failed to add label", (res == ERR_OK), return res);
return mdns_add_dotlocal(domain);
}

View file

@ -230,7 +230,8 @@ mdns_add_any_host_question(struct mdns_outpacket *outpkt,
u16_t request_unicast_reply)
{
struct mdns_domain host;
mdns_build_host_domain(&host, mdns);
const char* hostname = mdns->name;
mdns_build_host_domain(&host, hostname);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Adding host question for ANY type\n"));
return mdns_add_question(outpkt, &host, DNS_RRTYPE_ANY, DNS_RRCLASS_IN,
request_unicast_reply);
@ -258,7 +259,14 @@ 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(netif));
struct mdns_host* mdns = netif_mdns_data(netif);
const char* hostname = mdns->name;
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
if (msg->host_index > 0) {
hostname = mdns->secondary_hostnames[msg->host_index - 1];
}
#endif
mdns_build_host_domain(&host, hostname);
/* 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) {
@ -289,7 +297,10 @@ 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(netif));
struct mdns_host* mdns = netif_mdns_data(netif);
/* Always reply with the primary hostname for reverse lookups. */
const char* hostname = mdns->name;
mdns_build_host_domain(&host, hostname);
mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(netif));
/* When answering to a legacy querier, we need to repeat the question and
* limit the ttl to the short legacy ttl */
@ -322,7 +333,12 @@ mdns_add_aaaa_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(netif));
struct mdns_host* mdns = netif_mdns_data(netif);
const char* hostname = mdns->name;
if (reply->host_index > 0) {
hostname = mdns->secondary_hostnames[reply->host_index - 1];
}
mdns_build_host_domain(&host, hostname);
/* 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) {
@ -353,7 +369,10 @@ mdns_add_hostv6_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(netif));
struct mdns_host* mdns = netif_mdns_data(netif);
/* Always reply with the primary hostname for reverse lookups. */
const char* hostname = mdns->name;
mdns_build_host_domain(&host, hostname);
mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(netif, addrindex));
/* When answering to a legacy querier, we need to repeat the question and
* limit the ttl to the short legacy ttl */
@ -449,7 +468,9 @@ mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
struct mdns_domain service_instance, srvhost;
u16_t srvdata[3];
mdns_build_service_domain(&service_instance, service, 1);
mdns_build_host_domain(&srvhost, mdns);
/* Always reply with the primary hostname for services. */
const char* hostname = mdns->name;
mdns_build_host_domain(&srvhost, hostname);
if (msg->legacy_query) {
/* RFC 6762 section 18.14:
* In legacy unicast responses generated to answer legacy queries,

View file

@ -112,6 +112,11 @@ err_t mdns_resp_remove_netif(struct netif *netif);
err_t mdns_resp_rename_netif(struct netif *netif, const char *hostname);
int mdns_resp_netif_active(struct netif *netif);
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
err_t mdns_resp_add_secondary_hostname(struct netif *netif, const char* hostname);
err_t mdns_resp_del_secondary_hostname(struct netif *netif, const char* hostname);
#endif
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, u8_t slot);
err_t mdns_resp_rename_service(struct netif *netif, u8_t slot, const char *name);

View file

@ -62,7 +62,7 @@ err_t mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t
#if LWIP_IPV6
err_t mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr);
#endif
err_t mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns);
err_t mdns_build_host_domain(struct mdns_domain *domain, const char *hostname);
err_t mdns_build_dnssd_domain(struct mdns_domain *domain);
err_t mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name);
#if LWIP_MDNS_SEARCH

View file

@ -60,6 +60,14 @@
#define MDNS_MAX_SERVICES 1
#endif
/** The maximum number of secondary host names per netif. Secondary hostnames
* reply to hostname lookup requests but are not used in service replies. This
* is useful to share a hostname with multiple devices that redirect to their
* unique hostnames. */
#ifndef MDNS_MAX_SECONDARY_HOSTNAMES
#define MDNS_MAX_SECONDARY_HOSTNAMES 0
#endif
/** The minimum delay between probes in ms. RFC 6762 require 250ms.
* In noisy WiFi environment, adding 30-50ms to this value help a lot for
* a successful Apple BCT tests.

View file

@ -156,6 +156,8 @@ struct mdns_outmsg {
u8_t host_reverse_v6_replies;
/* Reply bitmask per service */
u8_t serv_replies[MDNS_MAX_SERVICES];
/* Hostname index to include in A and AAAA answers. 0 for name, 1+ for secondary_hostnames */
u8_t host_index;
#ifdef LWIP_MDNS_SEARCH
/** Search query to send */
struct mdns_request *query;
@ -201,6 +203,10 @@ typedef enum {
struct mdns_host {
/** Hostname */
char name[MDNS_LABEL_MAXLEN + 1];
#if MDNS_MAX_SECONDARY_HOSTNAMES > 0
/** Secondary hostnames to respond to */
char secondary_hostnames[MDNS_MAX_SECONDARY_HOSTNAMES][MDNS_LABEL_MAXLEN + 1];
#endif
/** Pointer to services */
struct mdns_service *services[MDNS_MAX_SERVICES];
/** Number of probes/announces sent for the current name */