dns: added one-shot multicast DNS queries

This commit is contained in:
goldsimon 2016-12-09 09:20:46 +01:00
parent 85817e7611
commit 5774fdfe75
5 changed files with 125 additions and 12 deletions

View File

@ -6,6 +6,9 @@ HISTORY
++ New features:
2016-12-09: Simon Goldschmidt
* dns.c: added one-shot multicast DNS queries
2016-11-24: Ambroz Bizjak, David van Moolenbroek
* tcp_out.c: Optimize passing contiguous nocopy buffers to tcp_write (bug #46290)

View File

@ -24,6 +24,11 @@
* the resolver code calls a specified callback function (which
* must be implemented by the module that uses the resolver).
*
* Multicast DNS queries are supported for names ending on ".local".
* However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762
* chapter 5.1), this is not a fully compliant implementation of continuous
* mDNS querying!
*
* All functions must be called from TCPIP thread.
*
* @see @ref netconn_common for thread-safe access.
@ -71,6 +76,7 @@
/** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */
/** @todo: one-shot mDNS: dual-stack fallback to another IP version */
/*-----------------------------------------------------------------------------
* Includes
@ -175,6 +181,12 @@ static u16_t dns_txid;
#define LWIP_DNS_SET_ADDRTYPE(x, y)
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
#define LWIP_DNS_ISMDNS_ARG(x) , x
#else
#define LWIP_DNS_ISMDNS_ARG(x)
#endif
/** DNS query message structure.
No packing needed: only used locally on the stack. */
struct dns_query {
@ -224,6 +236,9 @@ struct dns_table_entry {
#if LWIP_IPV4 && LWIP_IPV6
u8_t reqaddrtype;
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
};
/** DNS request table entry: used when dns_gehostbyname cannot answer the
@ -287,6 +302,13 @@ static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
#if LWIP_IPV4
const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
#endif /* LWIP_IPV6 */
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (if DNS_SERVER_ADDRESS is set).
@ -680,7 +702,11 @@ dns_send(u8_t idx)
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(entry->server_idx), entry->name));
LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
if (ip_addr_isany_val(dns_servers[entry->server_idx])) {
if (ip_addr_isany_val(dns_servers[entry->server_idx])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif
) {
/* DNS server not valid anymore, e.g. PPP netif has been shut down */
/* call specified callback function if provided */
dns_call_found(idx, NULL);
@ -693,6 +719,8 @@ dns_send(u8_t idx)
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
SIZEOF_DNS_QUERY), PBUF_RAM);
if (p != NULL) {
const ip_addr_t* dst;
u16_t dst_port;
/* fill dns header */
memset(&hdr, 0, SIZEOF_DNS_HDR);
hdr.id = lwip_htons(entry->txid);
@ -735,7 +763,30 @@ dns_send(u8_t idx)
/* send dns packet */
LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
entry->txid, entry->name, entry->server_idx));
err = udp_sendto(dns_pcbs[pcb_idx], p, &dns_servers[entry->server_idx], DNS_SERVER_PORT);
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (entry->is_mdns) {
dst_port = DNS_MQUERY_PORT;
#if LWIP_IPV6
if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
{
dst = &dns_mquery_v6group;
}
#endif
#if LWIP_IPV4 && LWIP_IPV6
else
#endif
#if LWIP_IPV4
{
dst = &dns_mquery_v4group;
}
#endif
} else
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
dst_port = DNS_SERVER_PORT;
dst = &dns_servers[entry->server_idx];
}
err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
/* free pbuf */
pbuf_free(p);
@ -938,7 +989,11 @@ dns_check_entry(u8_t i)
case DNS_STATE_ASKING:
if (--entry->tmr == 0) {
if (++entry->retries == DNS_MAX_RETRIES) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
) {
/* change of server */
entry->server_idx++;
entry->tmr = 1;
@ -1075,10 +1130,15 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
goto memerr; /* ignore this packet */
}
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (!entry->is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */
}
}
/* Check if the name in the "question" part match with the name in the entry and
@ -1210,7 +1270,7 @@ memerr:
*/
static err_t
dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
{
u8_t i;
u8_t lseq, lseqi;
@ -1326,6 +1386,10 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
#endif
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
entry->is_mdns = is_mdns;
#endif
dns_seqno++;
/* force to send query without waiting timer */
@ -1381,6 +1445,9 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
void *callback_arg, u8_t dns_addrtype)
{
size_t hostnamelen;
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
/* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */
if ((addr == NULL) ||
@ -1437,13 +1504,25 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
LWIP_UNUSED_ARG(dns_addrtype);
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL;
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
is_mdns = 1;
} else {
is_mdns = 0;
}
if (!is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL;
}
}
/* queue query with specified callback */
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
LWIP_DNS_ISMDNS_ARG(is_mdns));
}
#endif /* LWIP_DNS */

View File

@ -84,6 +84,13 @@ struct local_hostlist_entry {
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
#if LWIP_IPV4
extern const ip_addr_t dns_mquery_v4group;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
extern const ip_addr_t dns_mquery_v6group;
#endif /* LWIP_IPV6 */
/** Callback which is invoked when a hostname is found.
* A function of this type must be implemented by the application using the DNS resolver.
* @param name pointer to the name that was looked up.

View File

@ -1057,6 +1057,12 @@
#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__
#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
/** Set this to 1 to enable querying ".local" names via mDNS
* using a One-Shot Multicast DNS Query */
#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__
#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0
#endif
/**
* @}
*/

View File

@ -115,6 +115,24 @@ PACK_STRUCT_END
#endif
#define SIZEOF_DNS_HDR 12
/* Multicast DNS definitions */
/** UDP port for multicast DNS queries */
#ifndef DNS_MQUERY_PORT
#define DNS_MQUERY_PORT 5353
#endif
/* IPv4 group for multicast DNS queries: 224.0.0.251 */
#ifndef DNS_MQUERY_IPV4_GROUP_INIT
#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251)
#endif
/* IPv6 group for multicast DNS queries: FF02::FB */
#ifndef DNS_MQUERY_IPV6_GROUP_INIT
#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB)
#endif
#ifdef __cplusplus
}
#endif