samples: net: dns: Add mDNS client support to DNS resolver sample

The DNS resolver example enables mDNS client support and then
queries zephyr.local hostname. The net-tools project has example
avahi-daemon script that will response these .local queries and
can be used in testing.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-09-03 22:12:23 +03:00 committed by Anas Nashif
commit af63ae28ec
3 changed files with 181 additions and 86 deletions

View file

@ -13,6 +13,10 @@ If a CNAME is received, the DNS resolver will create another DNS query.
The number of additional queries is controlled by the
DNS_RESOLVER_ADDITIONAL_QUERIES Kconfig variable.
The multicast DNS (mDNS) client resolver support can be enabled by setting
CONFIG_MDNS_RESOLVER Kconfig variable.
See https://tools.ietf.org/html/rfc6762 for more details about mDNS.
For more information about DNS configuration variables, see:
:file:`subsys/net/lib/dns/Kconfig`. The DNS resolver API can be found at
:file:`include/net/dns_resolve.h`. The sample code can be found at:
@ -34,28 +38,6 @@ Requirements
dnsmasq -v
Dnsmasq version 2.76 Copyright (c) 2000-2016 Simon Kelley
Wiring
******
The ENC28J60 module is an Ethernet device with SPI interface.
The following pins must be connected from the ENC28J60 device to the
Arduino 101 board:
=========== ===================================
Arduino 101 ENC28J60 (pin numbers on the board)
=========== ===================================
D13 SCK (1)
D12 SO (3)
D11 SI (2)
D10 CS (7)
D04 INT (5)
3.3V VCC (10)
GDN GND (9)
=========== ===================================
Building and Running
********************
@ -90,9 +72,7 @@ Open a terminal window and type:
.. code-block:: console
$ cd net-tools
$ ./dnsmasq.sh
('su' or 'sudo' may be required.)
$ sudo ./dnsmasq.sh
The default project configurations settings for this sample uses the public
Google DNS servers. In order to use the local dnsmasq server, please edit
@ -122,9 +102,15 @@ Open a terminal window and type:
$ killall -s KILL dnsmasq
Try to launch the dnsmasq application again.
For testing mDNS, use Avahi script in net-tools project:
.. code-block:: console
$ cd net-tools
$ ./avahi-daemon.sh
QEMU x86
========
@ -186,3 +172,19 @@ Open a terminal window and type:
Use 'dmesg' to find the right USB device.
Once the binary is loaded into the Arduino 101 board, press the RESET button.
The ENC28J60 module is an Ethernet device with SPI interface.
The following pins must be connected from the ENC28J60 device to the
Arduino 101 board:
=========== ===================================
Arduino 101 ENC28J60 (pin numbers on the board)
=========== ===================================
D13 SCK (1)
D12 SO (3)
D11 SI (2)
D10 CS (7)
D04 INT (5)
3.3V VCC (10)
GDN GND (9)
=========== ===================================

View file

@ -3,19 +3,19 @@ CONFIG_NET_UDP=y
CONFIG_RANDOM_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_INIT_STACKS=y
CONFIG_NET_PKT_RX_COUNT=4
CONFIG_NET_PKT_TX_COUNT=4
CONFIG_NET_BUF_RX_COUNT=14
CONFIG_NET_BUF_TX_COUNT=14
CONFIG_NET_PKT_RX_COUNT=10
CONFIG_NET_PKT_TX_COUNT=10
CONFIG_NET_BUF_RX_COUNT=10
CONFIG_NET_BUF_TX_COUNT=10
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5
CONFIG_NET_LOG=y
CONFIG_SYS_LOG=y
CONFIG_SYS_LOG_NET_LEVEL=4
CONFIG_SYS_LOG_NET_LEVEL=2
CONFIG_SYS_LOG_SHOW_COLOR=y
#CONFIG_NET_DEBUG_NET_PKT=y
CONFIG_NET_DEBUG_NET_PKT=y
CONFIG_NET_DEBUG_DNS_RESOLVE=y
#CONFIG_NET_DEBUG_CONTEXT=y
#CONFIG_NET_DEBUG_CORE=y
@ -24,27 +24,35 @@ CONFIG_NET_DEBUG_DNS_RESOLVE=y
#CONFIG_NET_DEBUG_IPV6=y
#CONFIG_NET_DEBUG_UDP=y
#CONFIG_NET_DEBUG_DHCPV4=y
#CONFIG_SLIP_DEBUG=y
#CONFIG_NET_DEBUG_L2_ETHERNET=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=n
# Enable the DNS resolver
CONFIG_DNS_RESOLVER=y
# Enable additional buffers
CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR=2
CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR=5
# Enable additional queries
CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2
# Enable mDNS support
CONFIG_MDNS_RESOLVER=y
CONFIG_DNS_RESOLVER_MAX_SERVERS=2
CONFIG_DNS_SERVER_IP_ADDRESSES=y
CONFIG_DNS_NUM_CONCUR_QUERIES=2
CONFIG_DNS_NUM_CONCUR_QUERIES=5
# Use local dnsmasq server for testing
CONFIG_DNS_SERVER1="[2001:db8::2]:15353"
CONFIG_DNS_SERVER2="192.0.2.2:15353"
# Google DNS IPv4 and IPv6 servers
CONFIG_DNS_SERVER1="8.8.8.8"
CONFIG_DNS_SERVER2="2001:4860:4860::8888"
#CONFIG_DNS_SERVER1="8.8.8.8"
#CONFIG_DNS_SERVER2="2001:4860:4860::8888"
CONFIG_NET_DHCPV4=y
# Router is needed when resolving using external DNS servers
CONFIG_NET_APP_NEED_IPV6_ROUTER=n
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
@ -52,7 +60,11 @@ CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_SHELL=y
CONFIG_NET_APP_SETTINGS=y
CONFIG_NET_APP_NEED_IPV6=y
CONFIG_NET_APP_NEED_IPV4=y
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
CONFIG_MAIN_STACK_SIZE=1504

View file

@ -20,7 +20,18 @@
#include <net/net_mgmt.h>
#include <net/dns_resolve.h>
#define DNS_TIMEOUT 2000 /* ms */
#if defined(CONFIG_MDNS_RESOLVER)
#if defined(CONFIG_NET_IPV4)
static struct k_delayed_work mdns_ipv4_timer;
static void do_mdns_ipv4_lookup(struct k_work *work);
#endif
#if defined(CONFIG_NET_IPV6)
static struct k_delayed_work mdns_ipv6_timer;
static void do_mdns_ipv6_lookup(struct k_work *work);
#endif
#endif
#define DNS_TIMEOUT K_SECONDS(2)
void dns_result_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
@ -54,6 +65,64 @@ void dns_result_cb(enum dns_resolve_status status,
return;
}
if (info->ai_family == AF_INET) {
hr_family = "IPv4";
addr = &net_sin(&info->ai_addr)->sin_addr;
#if defined(CONFIG_MDNS_RESOLVER) && defined(CONFIG_NET_IPV4)
k_delayed_work_init(&mdns_ipv4_timer, do_mdns_ipv4_lookup);
k_delayed_work_submit(&mdns_ipv4_timer, 0);
#endif
} else if (info->ai_family == AF_INET6) {
hr_family = "IPv6";
addr = &net_sin6(&info->ai_addr)->sin6_addr;
#if defined(CONFIG_MDNS_RESOLVER) && defined(CONFIG_NET_IPV6)
k_delayed_work_init(&mdns_ipv6_timer, do_mdns_ipv6_lookup);
k_delayed_work_submit(&mdns_ipv6_timer, 0);
#endif
} else {
NET_ERR("Invalid IP address family %d", info->ai_family);
return;
}
NET_INFO("%s %s address: %s", user_data ? (char *)user_data : "<null>", hr_family,
net_addr_ntop(info->ai_family, addr,
hr_addr, sizeof(hr_addr)));
}
void mdns_result_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
char hr_addr[NET_IPV6_ADDR_LEN];
char *hr_family;
void *addr;
switch (status) {
case DNS_EAI_CANCELED:
NET_INFO("DNS query was canceled");
return;
case DNS_EAI_FAIL:
NET_INFO("DNS resolve failed");
return;
case DNS_EAI_NODATA:
NET_INFO("Cannot resolve address");
return;
case DNS_EAI_ALLDONE:
NET_INFO("DNS resolving finished");
return;
case DNS_EAI_INPROGRESS:
break;
default:
NET_INFO("DNS resolving error (%d)", status);
return;
}
if (!info) {
return;
}
if (info->ai_family == AF_INET) {
hr_family = "IPv4";
addr = &net_sin(&info->ai_addr)->sin_addr;
@ -65,7 +134,7 @@ void dns_result_cb(enum dns_resolve_status status,
return;
}
NET_INFO("%s address: %s", hr_family,
NET_INFO("%s %s address: %s", user_data ? (char *)user_data : "<null>", hr_family,
net_addr_ntop(info->ai_family, addr,
hr_addr, sizeof(hr_addr)));
}
@ -76,14 +145,15 @@ static struct k_delayed_work ipv4_timer;
static void do_ipv4_lookup(struct k_work *work)
{
static const char *query = "www.zephyrproject.org";
u16_t dns_id;
int ret;
ret = dns_get_addr_info("www.zephyrproject.org",
ret = dns_get_addr_info(query,
DNS_QUERY_TYPE_A,
&dns_id,
dns_result_cb,
NULL,
(void *)query,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv4 address (%d)", ret);
@ -147,6 +217,32 @@ static void setup_dhcpv4(struct net_if *iface)
#define setup_dhcpv4(...)
#endif /* CONFIG_NET_DHCPV4 */
#if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_DHCPV4)
#if defined(CONFIG_MDNS_RESOLVER)
static void do_mdns_ipv4_lookup(struct k_work *work)
{
static const char *query = "zephyr.local";
u16_t dns_id;
int ret;
NET_DBG("Doing mDNS IPv4 query");
ret = dns_get_addr_info(query,
DNS_QUERY_TYPE_A,
&dns_id,
mdns_result_cb,
(void *)query,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve mDNS IPv4 address (%d)", ret);
return;
}
NET_DBG("mDNS id %u", dns_id);
}
#endif
#endif
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_DHCPV4)
#if !defined(CONFIG_NET_APP_MY_IPV4_ADDR)
@ -155,6 +251,7 @@ static void setup_dhcpv4(struct net_if *iface)
static void setup_ipv4(struct net_if *iface)
{
static const char *query = "www.zephyrproject.org";
char hr_addr[NET_IPV4_ADDR_LEN];
struct in_addr addr;
u16_t dns_id;
@ -170,11 +267,11 @@ static void setup_ipv4(struct net_if *iface)
NET_INFO("IPv4 address: %s",
net_addr_ntop(AF_INET, &addr, hr_addr, NET_IPV4_ADDR_LEN));
ret = dns_get_addr_info("www.zephyrproject.org",
ret = dns_get_addr_info(query,
DNS_QUERY_TYPE_A,
&dns_id,
dns_result_cb,
NULL,
(void *)query,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv4 address (%d)", ret);
@ -194,19 +291,17 @@ static void setup_ipv4(struct net_if *iface)
#error "You need to define an IPv6 address!"
#endif
static struct net_mgmt_event_callback mgmt6_cb;
static struct k_delayed_work ipv6_timer;
static void do_ipv6_lookup(struct k_work *work)
static void do_ipv6_lookup(void)
{
static const char *query = "www.zephyrproject.org";
u16_t dns_id;
int ret;
ret = dns_get_addr_info("www.zephyrproject.org",
ret = dns_get_addr_info(query,
DNS_QUERY_TYPE_AAAA,
&dns_id,
dns_result_cb,
NULL,
(void *)query,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve IPv6 address (%d)", ret);
@ -216,48 +311,34 @@ static void do_ipv6_lookup(struct k_work *work)
NET_DBG("DNS id %u", dns_id);
}
/* DNS query will most probably fail if we do not have a default
* router configured because typically the DNS server is outside of local
* network. So wait for that before continuing.
*/
static void ipv6_router_add_handler(struct net_mgmt_event_callback *cb,
u32_t mgmt_event,
struct net_if *iface)
{
if (mgmt_event != NET_EVENT_IPV6_ROUTER_ADD) {
return;
}
/* We cannot run DNS lookup directly from this thread as the
* management event thread stack is very small by default.
* So run it from work queue instead.
*/
k_delayed_work_init(&ipv6_timer, do_ipv6_lookup);
k_delayed_work_submit(&ipv6_timer, 0);
}
static void setup_ipv6(struct net_if *iface)
{
char hr_addr[NET_IPV6_ADDR_LEN];
struct in6_addr addr;
do_ipv6_lookup();
}
if (net_addr_pton(AF_INET6, CONFIG_NET_APP_MY_IPV6_ADDR, &addr)) {
NET_ERR("Invalid address: %s", CONFIG_NET_APP_MY_IPV6_ADDR);
#if defined(CONFIG_MDNS_RESOLVER)
static void do_mdns_ipv6_lookup(struct k_work *work)
{
static const char *query = "zephyr.local";
u16_t dns_id;
int ret;
NET_DBG("Doing mDNS IPv6 query");
ret = dns_get_addr_info(query,
DNS_QUERY_TYPE_AAAA,
&dns_id,
mdns_result_cb,
(void *)query,
DNS_TIMEOUT);
if (ret < 0) {
NET_ERR("Cannot resolve mDNS IPv6 address (%d)", ret);
return;
}
net_mgmt_init_event_callback(&mgmt6_cb, ipv6_router_add_handler,
NET_EVENT_IPV6_ROUTER_ADD);
net_mgmt_add_event_callback(&mgmt6_cb);
net_if_ipv6_addr_add(iface, &addr, NET_ADDR_MANUAL, 0);
NET_INFO("IPv6 address: %s",
net_addr_ntop(AF_INET6, &addr, hr_addr, NET_IPV6_ADDR_LEN));
NET_INFO("Waiting for IPv6 default router notification "
"before issuing DNS query");
NET_DBG("mDNS id %u", dns_id);
}
#endif
#else
#define setup_ipv6(...)