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 #define DNS_SD_COUNT(dst) \
37 	STRUCT_SECTION_COUNT(dns_sd_rec, dst)
38 
39 #define DNS_SD_GET(i, dst) \
40 	STRUCT_SECTION_GET(dns_sd_rec, i, dst)
41 
42 /**
43  * @brief Extract labels from a DNS-SD PTR query
44  *
45  * ```
46  *            <sn>._tcp.<domain>.
47  * <instance>.<sn>._tcp.<domain>.
48  * ```
49  *
50  * Currently sub-types and service domains are unsupported and only the
51  * "local" domain is supported. Specifically, that excludes the following:
52  * ```
53  * <sub>._sub.<sn>._tcp.<servicedomain>.<parentdomain>.
54  * ```
55  *
56  * @param query a pointer to the start of the query
57  * @param query_size the number of bytes contained in the query
58  * @param[out] record the DNS-SD record to initialize and populate
59  * @param label array of pointers to suitably sized buffers
60  * @param size array of sizes for each buffer in @p label
61  * @param[inout] n number of elements in @p label and @p size
62  *
63  * @return on success, number of bytes read from @p query
64  * @return on failure, a negative errno value
65  *
66  * @see <a href="https://datatracker.ietf.org/doc/html/rfc6763">RFC 6763</a>, Section 7.2.
67  */
68 int dns_sd_query_extract(const uint8_t *query, size_t query_size, struct dns_sd_rec *record,
69 			 char **label, size_t *size, size_t *n);
70 
71 /**
72  * @brief See if the DNS SD @p filter matches the @p record
73  *
74  * The fields in @p filter should be populated with filter elements to
75  * identify a possible match. If pointer fields are set to NULL, they
76  * act as a wildcard in the matching process. I.e. they will match
77  * anything. Similarly, the @ref dns_sd_rec.port field may be set to 0
78  * to be used as a wildcard.
79  *
80  * The @ref dns_sd_rec.text and @ref dns_ds_rec.text_size fields
81  * are not included in the matching process.
82  *
83  * For example, the filter below can be used to match any
84  * "_http._tcp" records.
85  *
86  * @code{c}
87  * const struct dns_sd_rec *it;
88  * struct dns_sd_rec filter = {
89  *     // match any instance
90  *     .instance = NULL,
91  *     // match records with service "_http"
92  *     .service = "_http",
93  *     // match records with protocol "_tcp"
94  *     .proto = "_tcp",
95  *     // match any domain
96  *     .domain = NULL,
97  *     // match any port
98  *     .port = 0,
99  * };
100  *
101  * DNS_SD_FOREACH(it) {
102  *     if (dns_sd_rec_match(it, filter)) {
103  *         // found a match!
104  *     }
105  * }
106  * @endcode{c}
107  *
108  * @param record The reference DNS-SD record
109  * @param filter The DNS-SD record filter
110  *
111  * @return true if the @p record matches the @p filter
112  * @return false if @p record is not a match for @p filter
113  * @return false if either @p record or @p filter are invalid
114  */
115 bool dns_sd_rec_match(const struct dns_sd_rec *record,
116 	const struct dns_sd_rec *filter);
117 
118 /**
119  * @brief Handle a DNS PTR Query with DNS Service Discovery
120  *
121  * This function should be called once for each DNS-SD record that
122  * matches a particular DNS PTR query.
123  *
124  * If there is no IPv4 address to advertise, then @p addr4 should be
125  * NULL.
126  *
127  * If there is no IPv6 address to advertise, then @p addr6 should be
128  * NULL.
129  *
130  * @param inst the DNS-SD record to advertise
131  * @param addr4 pointer to the IPv4 address
132  * @param addr6 pointer to the IPv6 address
133  * @param buf output buffer
134  * @param buf_size size of the output buffer
135  *
136  * @return on success, number of bytes written to @p buf
137  * @return on failure, a negative errno value
138  */
139 int dns_sd_handle_ptr_query(const struct dns_sd_rec *inst,
140 	const struct in_addr *addr4, const struct in6_addr *addr6,
141 	uint8_t *buf, uint16_t buf_size);
142 
143 /**
144  * @brief Handle a Service Type Enumeration with DNS Service Discovery
145  *
146  * This function should be called once for each type of advertised service.
147  *
148  * @param service the DNS-SD service to advertise
149  * @param addr4 pointer to the IPv4 address
150  * @param addr6 pointer to the IPv6 address
151  * @param buf output buffer
152  * @param buf_size size of the output buffer
153  *
154  * @return on success, number of bytes written to @p buf
155  * @return on failure, a negative errno value
156  */
157 int dns_sd_handle_service_type_enum(const struct dns_sd_rec *service,
158 	const struct in_addr *addr4, const struct in6_addr *addr6,
159 	uint8_t *buf, uint16_t buf_size);
160 
161 #ifdef __cplusplus
162 };
163 #endif
164 
165 #endif /* DNS_SD_H_ */
166