]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | #pragma once | |
3 | ||
4 | #include <netinet/in.h> | |
5 | ||
6 | #include "dns-def.h" | |
7 | #include "dns-type.h" | |
8 | #include "list.h" | |
9 | #include "resolved-forward.h" | |
10 | ||
11 | /* DNSKEY RR flags */ | |
12 | #define DNSKEY_FLAG_SEP (UINT16_C(1) << 0) | |
13 | #define DNSKEY_FLAG_REVOKE (UINT16_C(1) << 7) | |
14 | #define DNSKEY_FLAG_ZONE_KEY (UINT16_C(1) << 8) | |
15 | ||
16 | /* mDNS RR flags */ | |
17 | #define MDNS_RR_CACHE_FLUSH_OR_QU (UINT16_C(1) << 15) | |
18 | ||
19 | /* DNSSEC algorithm identifiers, see | |
20 | * http://tools.ietf.org/html/rfc4034#appendix-A.1 and | |
21 | * https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ | |
22 | enum { | |
23 | DNSSEC_ALGORITHM_RSAMD5 = 1, | |
24 | DNSSEC_ALGORITHM_DH, | |
25 | DNSSEC_ALGORITHM_DSA, | |
26 | DNSSEC_ALGORITHM_ECC, | |
27 | DNSSEC_ALGORITHM_RSASHA1, | |
28 | DNSSEC_ALGORITHM_DSA_NSEC3_SHA1, | |
29 | DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, | |
30 | DNSSEC_ALGORITHM_RSASHA256 = 8, /* RFC 5702 */ | |
31 | DNSSEC_ALGORITHM_RSASHA512 = 10, /* RFC 5702 */ | |
32 | DNSSEC_ALGORITHM_ECC_GOST = 12, /* RFC 5933 */ | |
33 | DNSSEC_ALGORITHM_ECDSAP256SHA256 = 13, /* RFC 6605 */ | |
34 | DNSSEC_ALGORITHM_ECDSAP384SHA384 = 14, /* RFC 6605 */ | |
35 | DNSSEC_ALGORITHM_ED25519 = 15, /* RFC 8080 */ | |
36 | DNSSEC_ALGORITHM_ED448 = 16, /* RFC 8080 */ | |
37 | DNSSEC_ALGORITHM_INDIRECT = 252, | |
38 | DNSSEC_ALGORITHM_PRIVATEDNS, | |
39 | DNSSEC_ALGORITHM_PRIVATEOID, | |
40 | _DNSSEC_ALGORITHM_MAX_DEFINED | |
41 | }; | |
42 | ||
43 | /* DNSSEC digest identifiers, see | |
44 | * https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ | |
45 | enum { | |
46 | DNSSEC_DIGEST_SHA1 = 1, | |
47 | DNSSEC_DIGEST_SHA256 = 2, /* RFC 4509 */ | |
48 | DNSSEC_DIGEST_GOST_R_34_11_94 = 3, /* RFC 5933 */ | |
49 | DNSSEC_DIGEST_SHA384 = 4, /* RFC 6605 */ | |
50 | _DNSSEC_DIGEST_MAX_DEFINED | |
51 | }; | |
52 | ||
53 | /* DNSSEC NSEC3 hash algorithms, see | |
54 | * https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */ | |
55 | enum { | |
56 | NSEC3_ALGORITHM_SHA1 = 1, | |
57 | _NSEC3_ALGORITHM_MAX_DEFINED | |
58 | }; | |
59 | ||
60 | /* SSHFP algorithm identifiers, see | |
61 | * https://www.iana.org/assignments/dns-sshfp-rr-parameters/dns-sshfp-rr-parameters.xhtml */ | |
62 | enum { | |
63 | SSHFP_ALGORITHM_RSA = 1, /* RFC 4255 */ | |
64 | SSHFP_ALGORITHM_DSA = 2, /* RFC 4255 */ | |
65 | SSHFP_ALGORITHM_ECDSA = 3, /* RFC 6594 */ | |
66 | SSHFP_ALGORITHM_ED25519 = 4, /* RFC 7479 */ | |
67 | /* unassigned */ | |
68 | SSHFP_ALGORITHM_ED448 = 6, /* RFC 8709 */ | |
69 | _SSHFP_ALGORITHM_MAX_DEFINED | |
70 | }; | |
71 | /* A helper to align printed output */ | |
72 | #define SSHFP_ALGORITHM_FMT "%-7s" | |
73 | ||
74 | /* SSHFP key-type identifiers, see | |
75 | * https://www.iana.org/assignments/dns-sshfp-rr-parameters/dns-sshfp-rr-parameters.xhtml */ | |
76 | enum { | |
77 | SSHFP_KEY_TYPE_SHA1 = 1, /* RFC 4255 */ | |
78 | SSHFP_KEY_TYPE_SHA256 = 2, /* RFC 4255 */ | |
79 | _SSHFP_KEY_TYPE_MAX_DEFINED | |
80 | }; | |
81 | /* A helper to align printed output */ | |
82 | #define SSHFP_KEY_TYPE_FMT "%-7s" | |
83 | ||
84 | typedef struct DnsResourceKey { | |
85 | unsigned n_ref; /* (unsigned -1) for const keys, see below */ | |
86 | uint16_t class, type; | |
87 | char *_name; /* don't access directly, use dns_resource_key_name()! */ | |
88 | } DnsResourceKey; | |
89 | ||
90 | /* Creates a temporary resource key. This is only useful to quickly | |
91 | * look up something, without allocating a full DnsResourceKey object | |
92 | * for it. Note that it is not OK to take references to this kind of | |
93 | * resource key object. */ | |
94 | #define DNS_RESOURCE_KEY_CONST(c, t, n) \ | |
95 | ((DnsResourceKey) { \ | |
96 | .n_ref = UINT_MAX, \ | |
97 | .class = c, \ | |
98 | .type = t, \ | |
99 | ._name = (char*) n, \ | |
100 | }) | |
101 | ||
102 | typedef struct DnsTxtItem { | |
103 | size_t length; | |
104 | LIST_FIELDS(DnsTxtItem, items); | |
105 | uint8_t data[]; | |
106 | } DnsTxtItem; | |
107 | ||
108 | typedef struct DnsSvcParam { | |
109 | uint16_t key; | |
110 | size_t length; | |
111 | LIST_FIELDS(DnsSvcParam, params); | |
112 | union { | |
113 | DECLARE_FLEX_ARRAY(uint8_t, value); | |
114 | DECLARE_FLEX_ARRAY(struct in_addr, value_in_addr); | |
115 | DECLARE_FLEX_ARRAY(struct in6_addr, value_in6_addr); | |
116 | }; | |
117 | } DnsSvcParam; | |
118 | ||
119 | typedef struct DnsResourceRecord { | |
120 | unsigned n_ref; | |
121 | uint32_t ttl; | |
122 | usec_t expiry; /* RRSIG signature expiry */ | |
123 | ||
124 | DnsResourceKey *key; | |
125 | ||
126 | char *to_string; | |
127 | ||
128 | /* How many labels to strip to determine "signer" of the RRSIG (aka, the zone). -1 if not signed. */ | |
129 | uint8_t n_skip_labels_signer; | |
130 | /* How many labels to strip to determine "synthesizing source" of this RR, i.e. the wildcard's immediate parent. -1 if not signed. */ | |
131 | uint8_t n_skip_labels_source; | |
132 | ||
133 | bool unparsable; | |
134 | bool wire_format_canonical; | |
135 | ||
136 | void *wire_format; | |
137 | size_t wire_format_size; | |
138 | size_t wire_format_rdata_offset; | |
139 | ||
140 | union { | |
141 | struct { | |
142 | void *data; | |
143 | size_t data_size; | |
144 | } generic, opt; | |
145 | ||
146 | struct { | |
147 | char *name; | |
148 | uint16_t priority; | |
149 | uint16_t weight; | |
150 | uint16_t port; | |
151 | } srv; | |
152 | ||
153 | struct { | |
154 | char *name; | |
155 | } ptr, ns, cname, dname; | |
156 | ||
157 | struct { | |
158 | char *cpu; | |
159 | char *os; | |
160 | } hinfo; | |
161 | ||
162 | struct { | |
163 | DnsTxtItem *items; | |
164 | } txt, spf; | |
165 | ||
166 | struct { | |
167 | struct in_addr in_addr; | |
168 | } a; | |
169 | ||
170 | struct { | |
171 | struct in6_addr in6_addr; | |
172 | } aaaa; | |
173 | ||
174 | struct { | |
175 | char *mname; | |
176 | char *rname; | |
177 | uint32_t serial; | |
178 | uint32_t refresh; | |
179 | uint32_t retry; | |
180 | uint32_t expire; | |
181 | uint32_t minimum; | |
182 | } soa; | |
183 | ||
184 | struct { | |
185 | char *exchange; | |
186 | uint16_t priority; | |
187 | } mx; | |
188 | ||
189 | /* https://tools.ietf.org/html/rfc1876 */ | |
190 | struct { | |
191 | uint8_t version; | |
192 | uint8_t size; | |
193 | uint8_t horiz_pre; | |
194 | uint8_t vert_pre; | |
195 | uint32_t latitude; | |
196 | uint32_t longitude; | |
197 | uint32_t altitude; | |
198 | } loc; | |
199 | ||
200 | /* https://tools.ietf.org/html/rfc4255#section-3.1 */ | |
201 | struct { | |
202 | void *fingerprint; | |
203 | size_t fingerprint_size; | |
204 | ||
205 | uint8_t algorithm; | |
206 | uint8_t fptype; | |
207 | } sshfp; | |
208 | ||
209 | /* http://tools.ietf.org/html/rfc4034#section-2.1 */ | |
210 | struct { | |
211 | void* key; | |
212 | size_t key_size; | |
213 | ||
214 | uint16_t flags; | |
215 | uint8_t protocol; | |
216 | uint8_t algorithm; | |
217 | } dnskey; | |
218 | ||
219 | /* http://tools.ietf.org/html/rfc4034#section-3.1 */ | |
220 | struct { | |
221 | char *signer; | |
222 | void *signature; | |
223 | size_t signature_size; | |
224 | ||
225 | uint16_t type_covered; | |
226 | uint8_t algorithm; | |
227 | uint8_t labels; | |
228 | uint32_t original_ttl; | |
229 | uint32_t expiration; | |
230 | uint32_t inception; | |
231 | uint16_t key_tag; | |
232 | } rrsig; | |
233 | ||
234 | /* https://tools.ietf.org/html/rfc4034#section-4.1 */ | |
235 | struct { | |
236 | char *next_domain_name; | |
237 | Bitmap *types; | |
238 | } nsec; | |
239 | ||
240 | /* https://tools.ietf.org/html/rfc4034#section-5.1 */ | |
241 | struct { | |
242 | void *digest; | |
243 | size_t digest_size; | |
244 | ||
245 | uint16_t key_tag; | |
246 | uint8_t algorithm; | |
247 | uint8_t digest_type; | |
248 | } ds; | |
249 | ||
250 | struct { | |
251 | Bitmap *types; | |
252 | void *salt; | |
253 | size_t salt_size; | |
254 | void *next_hashed_name; | |
255 | size_t next_hashed_name_size; | |
256 | ||
257 | uint8_t algorithm; | |
258 | uint8_t flags; | |
259 | uint16_t iterations; | |
260 | } nsec3; | |
261 | ||
262 | /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23 */ | |
263 | struct { | |
264 | void *data; | |
265 | size_t data_size; | |
266 | ||
267 | uint8_t cert_usage; | |
268 | uint8_t selector; | |
269 | uint8_t matching_type; | |
270 | } tlsa; | |
271 | ||
272 | /* https://tools.ietf.org/html/rfc9460 */ | |
273 | struct { | |
274 | uint16_t priority; | |
275 | char *target_name; | |
276 | DnsSvcParam *params; | |
277 | } svcb, https; | |
278 | ||
279 | /* https://tools.ietf.org/html/rfc6844 */ | |
280 | struct { | |
281 | char *tag; | |
282 | void *value; | |
283 | size_t value_size; | |
284 | ||
285 | uint8_t flags; | |
286 | } caa; | |
287 | ||
288 | /* https://datatracker.ietf.org/doc/html/rfc2915 */ | |
289 | struct { | |
290 | uint16_t order; | |
291 | uint16_t preference; | |
292 | char *flags; | |
293 | char *services; | |
294 | char *regexp; | |
295 | char *replacement; | |
296 | } naptr; | |
297 | }; | |
298 | ||
299 | /* Note: fields should be ordered to minimize alignment gaps. Use pahole! */ | |
300 | } DnsResourceRecord; | |
301 | ||
302 | /* We use uint8_t for label counts above, and UINT8_MAX/-1 has special meaning. */ | |
303 | assert_cc(DNS_N_LABELS_MAX < UINT8_MAX); | |
304 | ||
305 | static inline const void* DNS_RESOURCE_RECORD_RDATA(const DnsResourceRecord *rr) { | |
306 | if (!rr) | |
307 | return NULL; | |
308 | ||
309 | if (!rr->wire_format) | |
310 | return NULL; | |
311 | ||
312 | assert(rr->wire_format_rdata_offset <= rr->wire_format_size); | |
313 | return (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset; | |
314 | } | |
315 | ||
316 | static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(const DnsResourceRecord *rr) { | |
317 | if (!rr) | |
318 | return 0; | |
319 | if (!rr->wire_format) | |
320 | return 0; | |
321 | ||
322 | assert(rr->wire_format_rdata_offset <= rr->wire_format_size); | |
323 | return rr->wire_format_size - rr->wire_format_rdata_offset; | |
324 | } | |
325 | ||
326 | static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(const DnsResourceRecord *rr) { | |
327 | assert(rr); | |
328 | assert(rr->key->type == DNS_TYPE_OPT); | |
329 | ||
330 | return ((rr->ttl >> 16) & 0xFF) == 0; | |
331 | } | |
332 | ||
333 | DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name); | |
334 | DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname); | |
335 | int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name); | |
336 | DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name); | |
337 | DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key); | |
338 | DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); | |
339 | ||
340 | #define DNS_RESOURCE_KEY_REPLACE(a, b) \ | |
341 | do { \ | |
342 | typeof(a)* _a = &(a); \ | |
343 | typeof(b) _b = (b); \ | |
344 | dns_resource_key_unref(*_a); \ | |
345 | *_a = _b; \ | |
346 | } while(0) | |
347 | ||
348 | const char* dns_resource_key_name(const DnsResourceKey *key); | |
349 | bool dns_resource_key_is_address(const DnsResourceKey *key); | |
350 | bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key); | |
351 | bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key); | |
352 | int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b); | |
353 | int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain); | |
354 | int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain); | |
355 | int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa); | |
356 | ||
357 | /* _DNS_{CLASS,TYPE}_STRING_MAX include one byte for NUL, which we use for space instead below. | |
358 | * DNS_HOSTNAME_MAX does not include the NUL byte, so we need to add 1. */ | |
359 | #define DNS_RESOURCE_KEY_STRING_MAX (_DNS_CLASS_STRING_MAX + _DNS_TYPE_STRING_MAX + DNS_HOSTNAME_MAX + 1) | |
360 | ||
361 | char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size); | |
362 | ssize_t dns_resource_record_payload(DnsResourceRecord *rr, const void **ret); | |
363 | ||
364 | #define DNS_RESOURCE_KEY_TO_STRING(key) \ | |
365 | dns_resource_key_to_string(key, (char[DNS_RESOURCE_KEY_STRING_MAX]) {}, DNS_RESOURCE_KEY_STRING_MAX) | |
366 | ||
367 | DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); | |
368 | ||
369 | static inline bool dns_key_is_shared(const DnsResourceKey *key) { | |
370 | return key->type == DNS_TYPE_PTR; | |
371 | } | |
372 | ||
373 | bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b); | |
374 | ||
375 | DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key); | |
376 | DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name); | |
377 | DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr); | |
378 | DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr); | |
379 | ||
380 | #define DNS_RR_REPLACE(a, b) \ | |
381 | do { \ | |
382 | typeof(a)* _a = &(a); \ | |
383 | typeof(b) _b = (b); \ | |
384 | dns_resource_record_unref(*_a); \ | |
385 | *_a = _b; \ | |
386 | } while(0) | |
387 | ||
388 | int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name); | |
389 | int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name); | |
390 | int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b); | |
391 | int dns_resource_record_payload_equal(const DnsResourceRecord *a, const DnsResourceRecord *b); | |
392 | ||
393 | const char* dns_resource_record_to_string(DnsResourceRecord *rr); | |
394 | DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr); | |
395 | DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); | |
396 | ||
397 | int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical); | |
398 | ||
399 | int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret); | |
400 | int dns_resource_record_source(DnsResourceRecord *rr, const char **ret); | |
401 | int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone); | |
402 | int dns_resource_record_is_synthetic(DnsResourceRecord *rr); | |
403 | ||
404 | int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl); | |
405 | ||
406 | bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr); | |
407 | ||
408 | int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord *cname, char **ret); | |
409 | ||
410 | DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); | |
411 | bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); | |
412 | DnsTxtItem *dns_txt_item_copy(DnsTxtItem *i); | |
413 | int dns_txt_item_new_empty(DnsTxtItem **ret); | |
414 | ||
415 | DnsSvcParam *dns_svc_param_free_all(DnsSvcParam *i); | |
416 | bool dns_svc_params_equal(DnsSvcParam *a, DnsSvcParam *b); | |
417 | DnsSvcParam *dns_svc_params_copy(DnsSvcParam *first); | |
418 | ||
419 | int dns_resource_record_new_from_raw(DnsResourceRecord **ret, const void *data, size_t size); | |
420 | ||
421 | int dns_resource_key_to_json(DnsResourceKey *key, sd_json_variant **ret); | |
422 | int dns_resource_key_from_json(sd_json_variant *v, DnsResourceKey **ret); | |
423 | int dns_resource_record_to_json(DnsResourceRecord *rr, sd_json_variant **ret); | |
424 | ||
425 | void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash *state); | |
426 | int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y); | |
427 | void dns_resource_record_hash_func(const DnsResourceRecord *i, struct siphash *state); | |
428 | int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y); | |
429 | ||
430 | extern const struct hash_ops dns_resource_key_hash_ops; | |
431 | extern const struct hash_ops dns_resource_record_hash_ops; | |
432 | extern const struct hash_ops dns_resource_record_hash_ops_by_key; | |
433 | ||
434 | int dnssec_algorithm_to_string_alloc(int i, char **ret); | |
435 | int dnssec_algorithm_from_string(const char *s) _pure_; | |
436 | ||
437 | int dnssec_digest_to_string_alloc(int i, char **ret); | |
438 | int dnssec_digest_from_string(const char *s) _pure_; | |
439 | ||
440 | int sshfp_algorithm_to_string_alloc(int i, char **ret); | |
441 | int sshfp_algorithm_from_string(const char *s) _pure_; | |
442 | ||
443 | int sshfp_key_type_to_string_alloc(int i, char **ret); | |
444 | int sshfp_key_type_from_string(const char *s) _pure_; |