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