Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: dns: dns-sd: support dns service discovery #29179

Merged
merged 4 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@
/subsys/net/buf.c @jukkar @jhedberg @tbursztyka @pfalcon
/subsys/net/ip/ @jukkar @tbursztyka @pfalcon
/subsys/net/lib/ @jukkar @tbursztyka @pfalcon
/subsys/net/lib/dns/ @jukkar @tbursztyka @pfalcon
/subsys/net/lib/dns/ @jukkar @tbursztyka @pfalcon @cfriedt
/subsys/net/lib/lwm2m/ @rlubos
/subsys/net/lib/config/ @jukkar @tbursztyka @pfalcon
/subsys/net/lib/mqtt/ @jukkar @tbursztyka @rlubos
Expand Down
4 changes: 4 additions & 0 deletions include/linker/common-rom.ld
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@
} GROUP_LINK_IN(ROMABLE_REGION)
#endif /* CONFIG_EMUL */

#if defined(CONFIG_DNS_SD)
Z_ITERABLE_SECTION_ROM(dns_sd_rec, 4)
#endif

SECTION_DATA_PROLOGUE(log_const_sections,,)
{
__log_const_start = .;
Expand Down
234 changes: 234 additions & 0 deletions include/net/dns_sd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
/** @file
* @brief DNS Service Discovery
*/

/*
* Copyright (c) 2020 Friedt Professional Engineering Services, Inc
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_NET_DNS_SD_H_
#define ZEPHYR_INCLUDE_NET_DNS_SD_H_

#include <stdint.h>
#include <sys/byteorder.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief DNS Service Discovery
*
* @details This API enables services to be advertised via DNS. To
* advvertise a service, system or application code should use
* @ref DNS_SD_REGISTER_TCP_SERVICE or
* @ref DNS_SD_REGISTER_UDP_SERVICE.
*
* @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
*
* @defgroup dns_sd DNS Service Discovery
* @ingroup networking
* @{
*/

/** RFC 1034 Section 3.1 */
#define DNS_SD_INSTANCE_MIN_SIZE 1
/** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
#define DNS_SD_INSTANCE_MAX_SIZE 63
/** RFC 6763 Section 7.2 - inclusive of underscore */
#define DNS_SD_SERVICE_MIN_SIZE 2
/** RFC 6763 Section 7.2 - inclusive of underscore */
#define DNS_SD_SERVICE_MAX_SIZE 16
/** RFC 6763 Section 4.1.2 */
#define DNS_SD_SERVICE_PREFIX '_'
/** RFC 6763 Section 4.1.2 - either _tcp or _udp (case insensitive) */
#define DNS_SD_PROTO_SIZE 4
/** ICANN Rules for TLD naming */
#define DNS_SD_DOMAIN_MIN_SIZE 2
/** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
#define DNS_SD_DOMAIN_MAX_SIZE 63

/**
* @brief Register a service for DNS Service Discovery
*
* This macro should be used for advanced use cases. Two simple use cases are
* when a custom @p domain or a custom (non-standard) @p proto is required.
*
* Another use case is when the port number is not preassigned. That could
* be for a number of reasons, but the most common use case would be for
* ephemeral port usage - i.e. when the service is bound using port number 0.
* In that case, Zephyr (like other OS's) will simply choose an unused port.
* When using ephemeral ports, it can be helpful to assign @p port to the
* @ref sockaddr_in.sin_port field of an IPv4 @ref sockaddr_in, or to the
* @ref sockaddr_in6.sin6_port field of an IPv6 @ref sockaddr_in6.
*
* The service can be referenced using the @p id variable.
*
* @param id variable name for the DNS-SD service record
* @param instance name of the service instance such as "My HTTP Server"
* @param service name of the service, such as "_http"
* @param proto protocol used by the service - either "_tcp" or "_udp"
* @param domain the domain of the service, such as "local"
* @param text information for the DNS TXT record
* @param port a pointer to the port number that this service will use
*/
#define DNS_SD_REGISTER_SERVICE(id, instance, service, proto, domain, \
text, port) \
static const Z_STRUCT_SECTION_ITERABLE(dns_sd_rec, id) = { \
instance, \
service, \
proto, \
domain, \
(const char *)text, \
sizeof(text) - 1, \
port \
}

/**
* @brief Register a TCP service for DNS Service Discovery
*
* This macro can be used for service advertisement using DNS-SD.
*
* The service can be referenced using the @p id variable.
*
* Example (with TXT):
* @code{c}
* #include <net/dns_sd.h>
* static const bar_txt[] = {
* "\x06" "path=/"
cfriedt marked this conversation as resolved.
Show resolved Hide resolved
* "\x0f" "this=is the way"
* "\x0e" "foo or=foo not"
* "\x17" "this=has\0embedded\0nulls"
* "\x04" "true"
* };
* // Possibly use an ephemeral port
* // Possibly only assign bar_port when the service is running
* static uint16_t bar_port;
* DNS_SD_REGISTER_TCP_SERVICE(bar, CONFIG_NET_HOSTNAME,
* "_bar", "local", bar_txt, &bar_port);
* @endcode{c}
*
* TXT records begin with a single length byte (hex-encoded)
* and contain key=value pairs. Thus, the length of the key-value pair
* must not exceed 255 bytes. Care must be taken to ensure that the
* encoded length value is correct.
*
* For additional rules on TXT encoding, see RFC 6763, Section 6.

* @param id variable name for the DNS-SD service record
* @param instance name of the service instance such as "My HTTP Server"
* @param service name of the service, such as "_http"
* @param domain the domain of the service, such as "local"
* @param text information for the DNS TXT record
* @param port the port number that this service will use
*
* @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
*/
#define DNS_SD_REGISTER_TCP_SERVICE(id, instance, service, domain, text, \
port) \
static const uint16_t id ## _port = sys_cpu_to_be16(port); \
DNS_SD_REGISTER_SERVICE(id, instance, service, "_tcp", domain, \
text, &id ## _port)

/**
* @brief Register a UDP service for DNS Service Discovery
*
* This macro can be used for service advertisement using DNS-SD.
*
* The service can be referenced using the @p id variable.
*
* Example (no TXT):
* @code{c}
* #include <net/dns_sd.h>
* #include <sys/byteorder.h>
* static const foo_port = sys_cpu_to_be16(4242);
* DNS_SD_REGISTER_UDP_SERVICE(foo, CONFIG_NET_HOSTNAME,
* "_foo", DNS_SD_EMPTY_TXT, &foo_port);
* @endcode{c}
*
* @param id variable name for the DNS-SD service record
* @param instance name of the service instance such as "My TFTP Server"
* @param service name of the service, such as "_tftp"
* @param domain the domain of the service, such as "local" or "zephyrproject.org"
* @param text information for the DNS TXT record
* @param port a pointer to the port number that this service will use
*
* @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
*/
#define DNS_SD_REGISTER_UDP_SERVICE(id, instance, service, domain, text, \
port) \
static const uint16_t id ## _port = sys_cpu_to_be16(port); \
DNS_SD_REGISTER_SERVICE(id, instance, service, "_udp", domain, \
text, &id ## _port)

/** Empty DNS-SD TXT specifier */
#define DNS_SD_EMPTY_TXT dns_sd_empty_txt

/** @cond INTERNAL_HIDDEN */

/**
* @brief DNS Service Discovery record
*
* This structure used in the implementation of RFC 6763 and should not
* need to be accessed directly from application code.
*
* The @a port pointer must be non-NULL. When the value in @a port
* is non-zero, the service is advertized as being on that particular
* port. When the value in @a port is zero, then the service is not
* advertised.
*
* Thus, it is possible for multiple services to advertise on a
* particular port if they hard-code the port.
*
* @internal
*
* @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
*/
struct dns_sd_rec {
/** <Instance> - e.g. "My HTTP Server" */
const char *instance;
/** Top half of the <Service> such as "_http" */
const char *service;
/** Bottom half of the <Service> "_tcp" or "_udp" */
const char *proto;
/** <Domain> such as "local" or "zephyrproject.org" */
const char *domain;
/** DNS TXT record */
const char *text;
/** Size (in bytes) of the DNS TXT record */
size_t text_size;
/** A pointer to the port number used by the service */
const uint16_t *port;
};

/**
* @brief Empty TXT specifier for DNS-SD
*
* @internal
*/
extern const char dns_sd_empty_txt[1];

/** @endcond */

/**
* @brief Obtain the size of DNS-SD TXT data
*
* @param rec the record to in question
* @return the size of the text field
*/
static inline size_t dns_sd_txt_size(const struct dns_sd_rec *rec)
{
return rec->text_size;
}

/**
* @}
*/

#ifdef __cplusplus
};
#endif

#endif /* ZEPHYR_INCLUDE_NET_DNS_SD_H_ */
16 changes: 16 additions & 0 deletions include/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,22 @@ static inline void net_context_setup_pools(struct net_context *context,
#define net_context_setup_pools(context, tx_pool, data_pool)
#endif

/**
* @brief Check if a port is in use (bound)
*
* This function checks if a port is bound with respect to the specified
* @p ip_proto and @p local_addr.
*
* @param ip_proto the IP protocol
* @param local_port the port to check
* @param local_addr the network address
*
* @return true if the port is bound
* @return false if the port is not bound
*/
bool net_context_port_in_use(enum net_ip_protocol ip_proto,
uint16_t local_port, const struct sockaddr *local_addr);

#ifdef __cplusplus
}
#endif
Expand Down
19 changes: 18 additions & 1 deletion samples/net/mdns_responder/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Build and run the mdns-responder sample application like this:
:goals: build
:compact:

After the mdns-responder sample application is started, it will wait queries
After the mdns-responder sample application is started, it will await queries
from the network.

Open a terminal window in your host and type:
Expand All @@ -56,3 +56,20 @@ If the query is successful, then following information is printed:
.. code-block:: console

zephyr.local 2001:db8::1

Lastly, resolve services using DNS Service Discovery:

.. code-block:: console

$ avahi-browse -t -r _zephyr._tcp

If the query is successful, then the following information is printed:

.. code-block:: console

+ zeth IPv6 zephyr _zephyr._tcp local
= zeth IPv6 zephyr _zephyr._tcp local
hostname = [zephyr.local]
address = [192.0.2.1]
port = [4242]
txt = []
11 changes: 11 additions & 0 deletions samples/net/mdns_responder/overlay-802154.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CONFIG_NET_IPV4=n
CONFIG_NET_CONFIG_NEED_IPV4=n
CONFIG_NET_CONFIG_MY_IPV4_ADDR=""
CONFIG_NET_CONFIG_PEER_IPV4_ADDR=""
CONFIG_NET_CONFIG_MY_IPV4_GW=""

CONFIG_NET_L2_IEEE802154=y
CONFIG_NET_L2_IEEE802154_SHELL=y
CONFIG_NET_L2_IEEE802154_LOG_LEVEL_INF=y

CONFIG_NET_CONFIG_IEEE802154_CHANNEL=26
17 changes: 17 additions & 0 deletions samples/net/mdns_responder/overlay-bt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
CONFIG_BT_DEVICE_NAME="Zephyr Echo Server"
CONFIG_NET_L2_BT=y
CONFIG_NET_IPV4=n
CONFIG_NET_IPV6=y
CONFIG_NET_CONFIG_BT_NODE=y
CONFIG_NET_CONFIG_NEED_IPV6=y
CONFIG_NET_IPV4=n
CONFIG_NET_CONFIG_NEED_IPV4=n
CONFIG_NET_CONFIG_MY_IPV4_ADDR=""
CONFIG_NET_CONFIG_PEER_IPV4_ADDR=""
CONFIG_NET_CONFIG_MY_IPV4_GW=""
7 changes: 7 additions & 0 deletions samples/net/mdns_responder/overlay-qemu_cortex_m3_eth.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_QEMU_ETHERNET=y

CONFIG_ETH_STELLARIS=y

CONFIG_NET_SLIP_TAP=n
CONFIG_SLIP=n
5 changes: 5 additions & 0 deletions samples/net/mdns_responder/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ CONFIG_NET_HOSTNAME_UNIQUE=n
CONFIG_NET_HOSTNAME="zephyr"

CONFIG_MDNS_RESPONDER=y
CONFIG_DNS_SD=y
CONFIG_MDNS_RESPONDER_DNS_SD=y

CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
Expand All @@ -36,3 +38,6 @@ CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"

CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
3 changes: 3 additions & 0 deletions samples/net/mdns_responder/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ LOG_MODULE_REGISTER(net_mdns_responder_sample, LOG_LEVEL_DBG);
#include <zephyr.h>
#include <net/net_core.h>

extern void service(void);

/* Note that this application does not do anything itself.
* It is just a placeholder for waiting mDNS queries.
*/
void main(void)
{
LOG_INF("Waiting mDNS queries...");
service();
}
Loading