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 * @ingroup networking
33 * @{
34 */
35
36 /** RFC 1034 Section 3.1 */
37 #define DNS_SD_INSTANCE_MIN_SIZE 1
38 /** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
39 #define DNS_SD_INSTANCE_MAX_SIZE 63
40 /** RFC 6763 Section 7.2 - inclusive of underscore */
41 #define DNS_SD_SERVICE_MIN_SIZE 2
42 /** RFC 6763 Section 7.2 - inclusive of underscore */
43 #define DNS_SD_SERVICE_MAX_SIZE 16
44 /** RFC 6763 Section 4.1.2 */
45 #define DNS_SD_SERVICE_PREFIX '_'
46 /** RFC 6763 Section 4.1.2 - either _tcp or _udp (case insensitive) */
47 #define DNS_SD_PROTO_SIZE 4
48 /** ICANN Rules for TLD naming */
49 #define DNS_SD_DOMAIN_MIN_SIZE 2
50 /** RFC 1034 Section 3.1, RFC 6763 Section 7.2 */
51 #define DNS_SD_DOMAIN_MAX_SIZE 63
52
53 /**
54 * Minimum number of segments in a fully-qualified name
55 *
56 * This represents FQN's of the form below
57 * ```
58 * <sn>._tcp.<domain>.
59 * ```
60 * Currently sub-types and service domains are unsupported and only the
61 * "local" domain is supported. Specifically, that excludes the following:
62 * ```
63 * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
64 * ```
65 * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
66 */
67 #define DNS_SD_MIN_LABELS 3
68 /**
69 * Maximum number of segments in a fully-qualified name
70 *
71 * This represents FQN's of the form below
72 * ```
73 * <instance>.<sn>._tcp.<domain>.
74 * ```
75 *
76 * Currently sub-types and service domains are unsupported and only the
77 * "local" domain is supported. Specifically, that excludes the following:
78 * ```
79 * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
80 * ```
81 * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
82 */
83 #define DNS_SD_MAX_LABELS 4
84
85 /**
86 * @brief Register a service for DNS Service Discovery
87 *
88 * This macro should be used for advanced use cases. Two simple use cases are
89 * when a custom @p _domain or a custom (non-standard) @p _proto is required.
90 *
91 * Another use case is when the port number is not preassigned. That could
92 * be for a number of reasons, but the most common use case would be for
93 * ephemeral port usage - i.e. when the service is bound using port number 0.
94 * In that case, Zephyr (like other OS's) will simply choose an unused port.
95 * When using ephemeral ports, it can be helpful to assign @p _port to the
96 * @ref sockaddr_in.sin_port field of an IPv4 @ref sockaddr_in, or to the
97 * @ref sockaddr_in6.sin6_port field of an IPv6 @ref sockaddr_in6.
98 *
99 * The service can be referenced using the @p _id variable.
100 *
101 * @param _id variable name for the DNS-SD service record
102 * @param _instance name of the service instance such as "My HTTP Server"
103 * @param _service name of the service, such as "_http"
104 * @param _proto protocol used by the service - either "_tcp" or "_udp"
105 * @param _domain the domain of the service, such as "local"
106 * @param _text information for the DNS TXT record
107 * @param _port a pointer to the port number that this service will use
108 */
109 #define DNS_SD_REGISTER_SERVICE(_id, _instance, _service, _proto, \
110 _domain, _text, _port) \
111 static const STRUCT_SECTION_ITERABLE(dns_sd_rec, _id) = { \
112 .instance = _instance, \
113 .service = _service, \
114 .proto = _proto, \
115 .domain = _domain, \
116 .text = (const char *)_text, \
117 .text_size = sizeof(_text) - 1, \
118 .port = _port, \
119 }
120
121 /**
122 * @brief Register a TCP service for DNS Service Discovery
123 *
124 * This macro can be used for service advertisement using DNS-SD.
125 *
126 * The service can be referenced using the @p id variable.
127 *
128 * Example (with TXT):
129 * @code{c}
130 * #include <zephyr/net/dns_sd.h>
131 * static const bar_txt[] = {
132 * "\x06" "path=/"
133 * "\x0f" "this=is the way"
134 * "\x0e" "foo or=foo not"
135 * "\x17" "this=has\0embedded\0nulls"
136 * "\x04" "true"
137 * };
138 * // Possibly use an ephemeral port
139 * // Possibly only assign bar_port when the service is running
140 * static uint16_t bar_port;
141 * DNS_SD_REGISTER_TCP_SERVICE(bar, CONFIG_NET_HOSTNAME,
142 * "_bar", "local", bar_txt, &bar_port);
143 * @endcode{c}
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 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 * #include <zephyr/sys/byteorder.h>
178 * static const foo_port = sys_cpu_to_be16(4242);
179 * DNS_SD_REGISTER_UDP_SERVICE(foo, CONFIG_NET_HOSTNAME,
180 * "_foo", DNS_SD_EMPTY_TXT, &foo_port);
181 * @endcode{c}
182 *
183 * @param id variable name for the DNS-SD service record
184 * @param instance name of the service instance such as "My TFTP Server"
185 * @param service name of the service, such as "_tftp"
186 * @param domain the domain of the service, such as "local" or "zephyrproject.org"
187 * @param text information for the DNS TXT record
188 * @param port a pointer to the port number that this service will use
189 *
190 * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
191 */
192 #define DNS_SD_REGISTER_UDP_SERVICE(id, instance, service, domain, text, \
193 port) \
194 static const uint16_t id ## _port = sys_cpu_to_be16(port); \
195 DNS_SD_REGISTER_SERVICE(id, instance, service, "_udp", domain, \
196 text, &id ## _port)
197
198 /** Empty DNS-SD TXT specifier */
199 #define DNS_SD_EMPTY_TXT dns_sd_empty_txt
200
201 /** @cond INTERNAL_HIDDEN */
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 * @internal
218 *
219 * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
220 */
221 struct dns_sd_rec {
222 /** <Instance> - e.g. "My HTTP Server" */
223 const char *instance;
224 /** Top half of the <Service> such as "_http" */
225 const char *service;
226 /** Bottom half of the <Service> "_tcp" or "_udp" */
227 const char *proto;
228 /** <Domain> such as "local" or "zephyrproject.org" */
229 const char *domain;
230 /** DNS TXT record */
231 const char *text;
232 /** Size (in bytes) of the DNS TXT record */
233 size_t text_size;
234 /** A pointer to the port number used by the service */
235 const uint16_t *port;
236 };
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