1 /*
2  * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef DNS_SD_H_
8 #define DNS_SD_H_
9 
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <string.h>
13 
14 #include <zephyr/net/dns_sd.h>
15 #include <zephyr/net/net_ip.h>
16 #include <zephyr/sys/iterable_sections.h>
17 
18 #include "dns_pack.h"
19 
20 /* TODO: Move these into Kconfig */
21 #define DNS_SD_PTR_TTL 4500
22 #define DNS_SD_TXT_TTL 4500
23 #define DNS_SD_SRV_TTL 120
24 #define DNS_SD_A_TTL 120
25 #define DNS_SD_AAAA_TTL 120
26 
27 #define DNS_SD_PTR_MASK (NS_CMPRSFLGS << 8)
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 #define DNS_SD_FOREACH(it) \
34 	STRUCT_SECTION_FOREACH(dns_sd_rec, it)
35 
36 /**
37  * @brief Extract labels from a DNS-SD PTR query
38  *
39  * ```
40  *            <sn>._tcp.<domain>.
41  * <instance>.<sn>._tcp.<domain>.
42  * ```
43  *
44  * Currently sub-types and service domains are unsupported and only the
45  * "local" domain is supported. Specifically, that excludes the following:
46  * ```
47  * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
48  * ```
49  *
50  * @param query a pointer to the start of the query
51  * @param query_size the number of bytes contained in the query
52  * @param[out] record the DNS-SD record to initialize and populate
53  * @param label array of pointers to suitably sized buffers
54  * @param size array of sizes for each buffer in @p label
55  * @param[inout] n number of elements in @p label and @p size
56  *
57  * @return on success, number of bytes read from @p query
58  * @return on failure, a negative errno value
59  *
60  * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
61  */
62 int dns_sd_query_extract(const uint8_t *query, size_t query_size, struct dns_sd_rec *record,
63 			 char **label, size_t *size, size_t *n);
64 
65 /**
66  * @brief Extract the Service, Protocol, and Domain from a DNS-SD PTR query
67  *
68  * This function zero-initializes @p record and populates the appropriate
69  * fields so that @p record may be subsequently passed to @ref dns_sd_rec_match.
70  *
71  * If a query with a supported format is found, the function returns the
72  * length of the initial, variable-length portion of the query.
73  *
74  * For example, if the query begins with "._foo._tcp.local.", where
75  * the '.' character represents a length of the subsequent string value,
76  * then this function will return 17.
77  *
78  * @param query a pointer to the start of the query
79  * @param query_size the number of bytes contained in the query
80  * @param[out] record the DNS-SD record to initialize and populate
81  * @param service buffer to store the null-terminated service
82  * @param service_size the size of @p service
83  * @param proto buffer to store the null-terminated proto
84  * @param proto_size the size of @p proto
85  * @param domain buffer to store the null-terminated domain
86  * @param domain_size the size of @p domain
87  * @return on success, a positive number representing length of the query
88  * @return on failure, a negative errno value
89  */
90 __deprecated
91 int dns_sd_extract_service_proto_domain(const uint8_t *query,
92 	size_t query_size, struct dns_sd_rec *record, char *service,
93 	size_t service_size, char *proto, size_t proto_size,
94 	char *domain, size_t domain_size);
95 
96 /**
97  * @brief See if the DNS SD @p filter matches the @p record
98  *
99  * The fields in @p filter should be populated with filter elements to
100  * identify a possible match. If pointer fields are set to NULL, they
101  * act as a wildcard in the matching process. I.e. they will match
102  * anything. Similarly, the @ref dns_sd_rec.port field may be set to 0
103  * to be used as a wildcard.
104  *
105  * The @ref dns_sd_rec.text and @ref dns_ds_rec.text_size fields
106  * are not included in the matching process.
107  *
108  * For example, the filter below can be used to match any
109  * "_http._tcp" records.
110  *
111  * @code{c}
112  * const struct dns_sd_rec *it;
113  * struct dns_sd_rec filter = {
114  *     // match any instance
115  *     .instance = NULL,
116  *     // match records with service "_http"
117  *     .service = "_http",
118  *     // match records with protocol "_tcp"
119  *     .proto = "_tcp",
120  *     // match any domain
121  *     .domain = NULL,
122  *     // match any port
123  *     .port = 0,
124  * };
125  *
126  * DNS_SD_FOREACH(it) {
127  *     if (dns_sd_rec_match(it, filter)) {
128  *         // found a match!
129  *     }
130  * }
131  * @endcode{c}
132  *
133  * @param record The reference DNS-SD record
134  * @param filter The DNS-SD record filter
135  *
136  * @return true if the @p record matches the @p filter
137  * @return false if @p record is not a match for @p filter
138  * @return false if either @p record or @p filter are invalid
139  */
140 bool dns_sd_rec_match(const struct dns_sd_rec *record,
141 	const struct dns_sd_rec *filter);
142 
143 /**
144  * @brief Handle a DNS PTR Query with DNS Service Discovery
145  *
146  * This function should be called once for each DNS-SD record that
147  * matches a particular DNS PTR query.
148  *
149  * If there is no IPv4 address to advertise, then @p addr4 should be
150  * NULL.
151  *
152  * If there is no IPv6 address to advertise, then @p addr6 should be
153  * NULL.
154  *
155  * @param inst the DNS-SD record to advertise
156  * @param addr4 pointer to the IPv4 address
157  * @param addr6 pointer to the IPv6 address
158  * @param buf output buffer
159  * @param buf_size size of the output buffer
160  *
161  * @return on success, number of bytes written to @p buf
162  * @return on failure, a negative errno value
163  */
164 int dns_sd_handle_ptr_query(const struct dns_sd_rec *inst,
165 	const struct in_addr *addr4, const struct in6_addr *addr6,
166 	uint8_t *buf, uint16_t buf_size);
167 
168 /**
169  * @brief Handle a Service Type Enumeration with DNS Service Discovery
170  *
171  * This function should be called once for each type of advertised service.
172  *
173  * @param service the DNS-SD service to advertise
174  * @param addr4 pointer to the IPv4 address
175  * @param addr6 pointer to the IPv6 address
176  * @param buf output buffer
177  * @param buf_size size of the output buffer
178  *
179  * @return on success, number of bytes written to @p buf
180  * @return on failure, a negative errno value
181  */
182 int dns_sd_handle_service_type_enum(const struct dns_sd_rec *service,
183 	const struct in_addr *addr4, const struct in6_addr *addr6,
184 	uint8_t *buf, uint16_t buf_size);
185 
186 #ifdef __cplusplus
187 };
188 #endif
189 
190 #endif /* DNS_SD_H_ */
191