Line data Source code
1 1 : /** @file
2 : * @brief DNS Service Discovery
3 : */
4 :
5 : /*
6 : * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
7 : *
8 : * SPDX-License-Identifier: Apache-2.0
9 : */
10 :
11 : #ifndef ZEPHYR_INCLUDE_NET_DNS_SD_H_
12 : #define ZEPHYR_INCLUDE_NET_DNS_SD_H_
13 :
14 : #include <stdint.h>
15 : #include <zephyr/sys/byteorder.h>
16 : #include <zephyr/sys/iterable_sections.h>
17 :
18 : #ifdef __cplusplus
19 : extern "C" {
20 : #endif
21 :
22 : /**
23 : * @brief DNS Service Discovery
24 : *
25 : * @details This API enables services to be advertised via DNS. To
26 : * advertise a service, system or application code should use
27 : * @ref DNS_SD_REGISTER_TCP_SERVICE or
28 : * @ref DNS_SD_REGISTER_UDP_SERVICE.
29 : *
30 : * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
31 : *
32 : * @defgroup dns_sd DNS Service Discovery
33 : * @since 2.5
34 : * @version 0.8.0
35 : * @ingroup networking
36 : * @{
37 : */
38 :
39 : /** RFC 1034 Section 3.1 */
40 1 : #define DNS_SD_INSTANCE_MIN_SIZE 1
41 : /** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
42 1 : #define DNS_SD_INSTANCE_MAX_SIZE 63
43 : /** RFC 6763 Section 7.2 - inclusive of underscore */
44 1 : #define DNS_SD_SERVICE_MIN_SIZE 2
45 : /** RFC 6763 Section 7.2 - inclusive of underscore */
46 1 : #define DNS_SD_SERVICE_MAX_SIZE 16
47 : /** RFC 6763 Section 4.1.2 */
48 1 : #define DNS_SD_SERVICE_PREFIX '_'
49 : /** RFC 6763 Section 4.1.2 - either _tcp or _udp (case insensitive) */
50 1 : #define DNS_SD_PROTO_SIZE 4
51 : /** ICANN Rules for TLD naming */
52 1 : #define DNS_SD_DOMAIN_MIN_SIZE 2
53 : /** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
54 1 : #define DNS_SD_DOMAIN_MAX_SIZE 63
55 :
56 : /**
57 : * Minimum number of segments in a fully-qualified name
58 : *
59 : * This represents FQN's of the form below
60 : * ```
61 : * <sn>._tcp.<domain>.
62 : * ```
63 : * Currently sub-types and service domains are unsupported and only the
64 : * "local" domain is supported. Specifically, that excludes the following:
65 : * ```
66 : * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
67 : * ```
68 : * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
69 : */
70 1 : #define DNS_SD_MIN_LABELS 3
71 : /**
72 : * Maximum number of segments in a fully-qualified name
73 : *
74 : * This represents FQN's of the form below
75 : * ```
76 : * <instance>.<sn>._tcp.<domain>.
77 : * ```
78 : *
79 : * Currently sub-types and service domains are unsupported and only the
80 : * "local" domain is supported. Specifically, that excludes the following:
81 : * ```
82 : * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
83 : * ```
84 : * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
85 : */
86 1 : #define DNS_SD_MAX_LABELS 4
87 :
88 : /**
89 : * @brief Register a service for DNS Service Discovery
90 : *
91 : * This macro should be used for advanced use cases. Two simple use cases are
92 : * when a custom @p _domain or a custom (non-standard) @p _proto is required.
93 : *
94 : * Another use case is when the port number is not preassigned. That could
95 : * be for a number of reasons, but the most common use case would be for
96 : * ephemeral port usage - i.e. when the service is bound using port number 0.
97 : * In that case, Zephyr (like other OS's) will simply choose an unused port.
98 : * When using ephemeral ports, it can be helpful to assign @p _port to the
99 : * @ref sockaddr_in.sin_port field of an IPv4 @ref sockaddr_in, or to the
100 : * @ref sockaddr_in6.sin6_port field of an IPv6 @ref sockaddr_in6.
101 : *
102 : * The service can be referenced using the @p _id variable.
103 : *
104 : * @param _id variable name for the DNS-SD service record
105 : * @param _instance name of the service instance such as "My HTTP Server"
106 : * @param _service name of the service, such as "_http"
107 : * @param _proto protocol used by the service - either "_tcp" or "_udp"
108 : * @param _domain the domain of the service, such as "local"
109 : * @param _text information for the DNS TXT record
110 : * @param _port a pointer to the port number that this service will use
111 : */
112 : #define DNS_SD_REGISTER_SERVICE(_id, _instance, _service, _proto, \
113 1 : _domain, _text, _port) \
114 : static const STRUCT_SECTION_ITERABLE(dns_sd_rec, _id) = { \
115 : .instance = _instance, \
116 : .service = _service, \
117 : .proto = _proto, \
118 : .domain = _domain, \
119 : .text = (const char *)_text, \
120 : .text_size = sizeof(_text) - 1, \
121 : .port = _port, \
122 : }
123 :
124 : /**
125 : * @brief Register a TCP service for DNS Service Discovery
126 : *
127 : * This macro can be used for service advertisement using DNS-SD.
128 : *
129 : * The service can be referenced using the @p id variable.
130 : *
131 : * Example (with TXT):
132 : * @code{.c}
133 : * #include <zephyr/net/dns_sd.h>
134 : * static const char bar_txt[] = {
135 : * "\x06" "path=/"
136 : * "\x0f" "this=is the way"
137 : * "\x0e" "foo or=foo not"
138 : * "\x17" "this=has\0embedded\0nulls"
139 : * "\x04" "true"
140 : * };
141 : * DNS_SD_REGISTER_TCP_SERVICE(bar, CONFIG_NET_HOSTNAME,
142 : * "_bar", "local", bar_txt, 4242);
143 : * @endcode
144 : *
145 : * TXT records begin with a single length byte (hex-encoded)
146 : * and contain key=value pairs. Thus, the length of the key-value pair
147 : * must not exceed 255 bytes. Care must be taken to ensure that the
148 : * encoded length value is correct.
149 : *
150 : * For additional rules on TXT encoding, see RFC 6763, Section 6.
151 :
152 : * @param id variable name for the DNS-SD service record
153 : * @param instance name of the service instance such as "My HTTP Server"
154 : * @param service name of the service, such as "_http"
155 : * @param domain the domain of the service, such as "local"
156 : * @param text information for the DNS TXT record
157 : * @param port the port number that this service will use
158 : *
159 : * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
160 : */
161 : #define DNS_SD_REGISTER_TCP_SERVICE(id, instance, service, domain, text, \
162 1 : port) \
163 : static const uint16_t id ## _port = sys_cpu_to_be16(port); \
164 : DNS_SD_REGISTER_SERVICE(id, instance, service, "_tcp", domain, \
165 : text, &id ## _port)
166 :
167 : /**
168 : * @brief Register a UDP service for DNS Service Discovery
169 : *
170 : * This macro can be used for service advertisement using DNS-SD.
171 : *
172 : * The service can be referenced using the @p id variable.
173 : *
174 : * Example (no TXT):
175 : * @code{.c}
176 : * #include <zephyr/net/dns_sd.h>
177 : * DNS_SD_REGISTER_UDP_SERVICE(foo, CONFIG_NET_HOSTNAME,
178 : * "_foo", "local", DNS_SD_EMPTY_TXT, 4242);
179 : * @endcode
180 : *
181 : * @param id variable name for the DNS-SD service record
182 : * @param instance name of the service instance such as "My TFTP Server"
183 : * @param service name of the service, such as "_tftp"
184 : * @param domain the domain of the service, such as "local" or "zephyrproject.org"
185 : * @param text information for the DNS TXT record
186 : * @param port a pointer to the port number that this service will use
187 : *
188 : * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
189 : */
190 : #define DNS_SD_REGISTER_UDP_SERVICE(id, instance, service, domain, text, \
191 1 : port) \
192 : static const uint16_t id ## _port = sys_cpu_to_be16(port); \
193 : DNS_SD_REGISTER_SERVICE(id, instance, service, "_udp", domain, \
194 : text, &id ## _port)
195 :
196 : /** Empty DNS-SD TXT specifier */
197 1 : #define DNS_SD_EMPTY_TXT dns_sd_empty_txt
198 :
199 : /**
200 : * @brief DNS Service Discovery record
201 : *
202 : * This structure used in the implementation of RFC 6763 and should not
203 : * need to be accessed directly from application code.
204 : *
205 : * The @a port pointer must be non-NULL. When the value in @a port
206 : * is non-zero, the service is advertised as being on that particular
207 : * port. When the value in @a port is zero, then the service is not
208 : * advertised.
209 : *
210 : * Thus, it is possible for multiple services to advertise on a
211 : * particular port if they hard-code the port.
212 : *
213 : * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
214 : */
215 1 : struct dns_sd_rec {
216 : /** "<Instance>" - e.g. "My HTTP Server" */
217 1 : const char *instance;
218 : /** Top half of the "<Service>" such as "_http" */
219 1 : const char *service;
220 : /** Bottom half of the "<Service>" "_tcp" or "_udp" */
221 1 : const char *proto;
222 : /** "<Domain>" such as "local" or "zephyrproject.org" */
223 1 : const char *domain;
224 : /** DNS TXT record */
225 1 : const char *text;
226 : /** Size (in bytes) of the DNS TXT record */
227 1 : size_t text_size;
228 : /** A pointer to the port number used by the service */
229 1 : const uint16_t *port;
230 : };
231 :
232 : /** @cond INTERNAL_HIDDEN */
233 :
234 : /**
235 : * @brief Empty TXT specifier for DNS-SD
236 : *
237 : * @internal
238 : */
239 : extern const char dns_sd_empty_txt[1];
240 : /**
241 : * @brief Wildcard Port specifier for DNS-SD
242 : *
243 : * @internal
244 : */
245 : extern const uint16_t dns_sd_port_zero;
246 :
247 : /** @endcond */
248 :
249 : /**
250 : * @brief Obtain the size of DNS-SD TXT data
251 : *
252 : * @param rec the record to in question
253 : * @return the size of the text field
254 : */
255 1 : static inline size_t dns_sd_txt_size(const struct dns_sd_rec *rec)
256 : {
257 : return rec->text_size;
258 : }
259 :
260 : /**
261 : * @brief Check if @a rec is a DNS-SD Service Type Enumeration
262 : *
263 : * DNS-SD Service Type Enumeration is used by network tooling to
264 : * acquire a list of all mDNS-advertised services belonging to a
265 : * particular host on a particular domain.
266 : *
267 : * For example, for the domain '.local', the equivalent query
268 : * would be '_services._dns-sd._udp.local'.
269 : *
270 : * Currently, only the '.local' domain is supported.
271 : *
272 : * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763#section-9">Service Type Enumeration, RFC 6763</a>.
273 : *
274 : * @param rec the record to in question
275 : * @return true if @a rec is a DNS-SD Service Type Enumeration
276 : */
277 1 : bool dns_sd_is_service_type_enumeration(const struct dns_sd_rec *rec);
278 :
279 : /**
280 : * @brief Create a wildcard filter for DNS-SD records
281 : *
282 : * @param filter a pointer to the filter to use
283 : */
284 1 : void dns_sd_create_wildcard_filter(struct dns_sd_rec *filter);
285 :
286 : /**
287 : * @}
288 : */
289 :
290 : #ifdef __cplusplus
291 : };
292 : #endif
293 :
294 : #endif /* ZEPHYR_INCLUDE_NET_DNS_SD_H_ */
|