zephyr/include/zephyr/net/dns_sd.h
Konrad Derda 42e6c1fbc6 net: mdns: add capability of providing records in runtime
Current implementation of mDNS responder does makes it mandatory to have
all the records set at compile time. It is not suited well for applications
that have to publish/unpublish or change records in runtime, e.g. data
received from the network.

Signed-off-by: Konrad Derda <konrad.derda@nordicsemi.no>
2024-03-22 12:41:56 +00:00

297 lines
9.2 KiB
C

/** @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 <zephyr/sys/byteorder.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief DNS Service Discovery
*
* @details This API enables services to be advertised via DNS. To
* advertise 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
/**
* Minimum number of segments in a fully-qualified name
*
* This represents FQN's of the form below
* ```
* <sn>._tcp.<domain>.
* ```
* Currently sub-types and service domains are unsupported and only the
* "local" domain is supported. Specifically, that excludes the following:
* ```
* <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
* ```
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
*/
#define DNS_SD_MIN_LABELS 3
/**
* Maximum number of segments in a fully-qualified name
*
* This represents FQN's of the form below
* ```
* <instance>.<sn>._tcp.<domain>.
* ```
*
* Currently sub-types and service domains are unsupported and only the
* "local" domain is supported. Specifically, that excludes the following:
* ```
* <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
* ```
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
*/
#define DNS_SD_MAX_LABELS 4
/**
* @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 STRUCT_SECTION_ITERABLE(dns_sd_rec, _id) = { \
.instance = _instance, \
.service = _service, \
.proto = _proto, \
.domain = _domain, \
.text = (const char *)_text, \
.text_size = sizeof(_text) - 1, \
.port = _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 <zephyr/net/dns_sd.h>
* static const bar_txt[] = {
* "\x06" "path=/"
* "\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 <zephyr/net/dns_sd.h>
* #include <zephyr/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
/**
* @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 advertised 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.
*
* @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;
};
/** @cond INTERNAL_HIDDEN */
/**
* @brief Empty TXT specifier for DNS-SD
*
* @internal
*/
extern const char dns_sd_empty_txt[1];
/**
* @brief Wildcard Port specifier for DNS-SD
*
* @internal
*/
extern const uint16_t dns_sd_port_zero;
/** @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;
}
/**
* @brief Check if @a rec is a DNS-SD Service Type Enumeration
*
* DNS-SD Service Type Enumeration is used by network tooling to
* acquire a list of all mDNS-advertised services belonging to a
* particular host on a particular domain.
*
* For example, for the domain '.local', the equivalent query
* would be '_services._dns-sd._udp.local'.
*
* Currently, only the '.local' domain is supported.
*
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6763#section-9">Service Type Enumeration, RFC 6763</a>.
*
* @param rec the record to in question
* @return true if @a rec is a DNS-SD Service Type Enumeration
*/
bool dns_sd_is_service_type_enumeration(const struct dns_sd_rec *rec);
/**
* @brief Create a wildcard filter for DNS-SD records
*
* @param filter a pointer to the filter to use
*/
void dns_sd_create_wildcard_filter(struct dns_sd_rec *filter);
/**
* @}
*/
#ifdef __cplusplus
};
#endif
#endif /* ZEPHYR_INCLUDE_NET_DNS_SD_H_ */