| File: | build-scan/../src/resolve/resolved-dns-rr.c |
| Warning: | line 815, column 24 Use of zero-allocated memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
| 2 | |||||
| 3 | #include <math.h> | ||||
| 4 | |||||
| 5 | #include "alloc-util.h" | ||||
| 6 | #include "dns-domain.h" | ||||
| 7 | #include "dns-type.h" | ||||
| 8 | #include "escape.h" | ||||
| 9 | #include "hexdecoct.h" | ||||
| 10 | #include "resolved-dns-dnssec.h" | ||||
| 11 | #include "resolved-dns-packet.h" | ||||
| 12 | #include "resolved-dns-rr.h" | ||||
| 13 | #include "string-table.h" | ||||
| 14 | #include "string-util.h" | ||||
| 15 | #include "strv.h" | ||||
| 16 | #include "terminal-util.h" | ||||
| 17 | |||||
| 18 | DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { | ||||
| 19 | DnsResourceKey *k; | ||||
| 20 | size_t l; | ||||
| 21 | |||||
| 22 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-rr.c" , 22, __PRETTY_FUNCTION__); } while (0); | ||||
| 23 | |||||
| 24 | l = strlen(name); | ||||
| 25 | k = malloc0(sizeof(DnsResourceKey) + l + 1)(calloc(1, (sizeof(DnsResourceKey) + l + 1))); | ||||
| 26 | if (!k) | ||||
| 27 | return NULL((void*)0); | ||||
| 28 | |||||
| 29 | k->n_ref = 1; | ||||
| 30 | k->class = class; | ||||
| 31 | k->type = type; | ||||
| 32 | |||||
| 33 | strcpy((char*) k + sizeof(DnsResourceKey), name); | ||||
| 34 | |||||
| 35 | return k; | ||||
| 36 | } | ||||
| 37 | |||||
| 38 | DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) { | ||||
| 39 | int r; | ||||
| 40 | |||||
| 41 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 41, __PRETTY_FUNCTION__); } while (0); | ||||
| 42 | assert(cname)do { if ((__builtin_expect(!!(!(cname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cname"), "../src/resolve/resolved-dns-rr.c" , 42, __PRETTY_FUNCTION__); } while (0); | ||||
| 43 | |||||
| 44 | assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DNS_TYPE_CNAME, DNS_TYPE_DNAME})/sizeof(int )]; switch(cname->key->type) { case DNS_TYPE_CNAME: case DNS_TYPE_DNAME: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)" ), "../src/resolve/resolved-dns-rr.c", 44, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 45 | |||||
| 46 | if (cname->key->type == DNS_TYPE_CNAME) | ||||
| 47 | return dns_resource_key_new(key->class, key->type, cname->cname.name); | ||||
| 48 | else { | ||||
| 49 | DnsResourceKey *k; | ||||
| 50 | char *destination = NULL((void*)0); | ||||
| 51 | |||||
| 52 | r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination); | ||||
| 53 | if (r < 0) | ||||
| 54 | return NULL((void*)0); | ||||
| 55 | if (r == 0) | ||||
| 56 | return dns_resource_key_ref((DnsResourceKey*) key); | ||||
| 57 | |||||
| 58 | k = dns_resource_key_new_consume(key->class, key->type, destination); | ||||
| 59 | if (!k) | ||||
| 60 | return mfree(destination); | ||||
| 61 | |||||
| 62 | return k; | ||||
| 63 | } | ||||
| 64 | } | ||||
| 65 | |||||
| 66 | int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) { | ||||
| 67 | DnsResourceKey *new_key; | ||||
| 68 | char *joined; | ||||
| 69 | int r; | ||||
| 70 | |||||
| 71 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-rr.c" , 71, __PRETTY_FUNCTION__); } while (0); | ||||
| 72 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 72, __PRETTY_FUNCTION__); } while (0); | ||||
| 73 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-rr.c" , 73, __PRETTY_FUNCTION__); } while (0); | ||||
| 74 | |||||
| 75 | if (dns_name_is_root(name)) { | ||||
| 76 | *ret = dns_resource_key_ref(key); | ||||
| 77 | return 0; | ||||
| 78 | } | ||||
| 79 | |||||
| 80 | r = dns_name_concat(dns_resource_key_name(key), name, &joined); | ||||
| 81 | if (r < 0) | ||||
| 82 | return r; | ||||
| 83 | |||||
| 84 | new_key = dns_resource_key_new_consume(key->class, key->type, joined); | ||||
| 85 | if (!new_key) { | ||||
| 86 | free(joined); | ||||
| 87 | return -ENOMEM12; | ||||
| 88 | } | ||||
| 89 | |||||
| 90 | *ret = new_key; | ||||
| 91 | return 0; | ||||
| 92 | } | ||||
| 93 | |||||
| 94 | DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) { | ||||
| 95 | DnsResourceKey *k; | ||||
| 96 | |||||
| 97 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-rr.c" , 97, __PRETTY_FUNCTION__); } while (0); | ||||
| 98 | |||||
| 99 | k = new0(DnsResourceKey, 1)((DnsResourceKey*) calloc((1), sizeof(DnsResourceKey))); | ||||
| 100 | if (!k) | ||||
| 101 | return NULL((void*)0); | ||||
| 102 | |||||
| 103 | k->n_ref = 1; | ||||
| 104 | k->class = class; | ||||
| 105 | k->type = type; | ||||
| 106 | k->_name = name; | ||||
| 107 | |||||
| 108 | return k; | ||||
| 109 | } | ||||
| 110 | |||||
| 111 | DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) { | ||||
| 112 | |||||
| 113 | if (!k) | ||||
| 114 | return NULL((void*)0); | ||||
| 115 | |||||
| 116 | /* Static/const keys created with DNS_RESOURCE_KEY_CONST will | ||||
| 117 | * set this to -1, they should not be reffed/unreffed */ | ||||
| 118 | assert(k->n_ref != (unsigned) -1)do { if ((__builtin_expect(!!(!(k->n_ref != (unsigned) -1) ),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("k->n_ref != (unsigned) -1" ), "../src/resolve/resolved-dns-rr.c", 118, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 119 | |||||
| 120 | assert(k->n_ref > 0)do { if ((__builtin_expect(!!(!(k->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("k->n_ref > 0"), "../src/resolve/resolved-dns-rr.c" , 120, __PRETTY_FUNCTION__); } while (0); | ||||
| 121 | k->n_ref++; | ||||
| 122 | |||||
| 123 | return k; | ||||
| 124 | } | ||||
| 125 | |||||
| 126 | DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { | ||||
| 127 | if (!k) | ||||
| 128 | return NULL((void*)0); | ||||
| 129 | |||||
| 130 | assert(k->n_ref != (unsigned) -1)do { if ((__builtin_expect(!!(!(k->n_ref != (unsigned) -1) ),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("k->n_ref != (unsigned) -1" ), "../src/resolve/resolved-dns-rr.c", 130, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 131 | assert(k->n_ref > 0)do { if ((__builtin_expect(!!(!(k->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("k->n_ref > 0"), "../src/resolve/resolved-dns-rr.c" , 131, __PRETTY_FUNCTION__); } while (0); | ||||
| 132 | |||||
| 133 | if (k->n_ref == 1) { | ||||
| 134 | free(k->_name); | ||||
| 135 | free(k); | ||||
| 136 | } else | ||||
| 137 | k->n_ref--; | ||||
| 138 | |||||
| 139 | return NULL((void*)0); | ||||
| 140 | } | ||||
| 141 | |||||
| 142 | const char* dns_resource_key_name(const DnsResourceKey *key) { | ||||
| 143 | const char *name; | ||||
| 144 | |||||
| 145 | if (!key) | ||||
| 146 | return NULL((void*)0); | ||||
| 147 | |||||
| 148 | if (key->_name) | ||||
| 149 | name = key->_name; | ||||
| 150 | else | ||||
| 151 | name = (char*) key + sizeof(DnsResourceKey); | ||||
| 152 | |||||
| 153 | if (dns_name_is_root(name)) | ||||
| 154 | return "."; | ||||
| 155 | else | ||||
| 156 | return name; | ||||
| 157 | } | ||||
| 158 | |||||
| 159 | bool_Bool dns_resource_key_is_address(const DnsResourceKey *key) { | ||||
| 160 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 160, __PRETTY_FUNCTION__); } while (0); | ||||
| 161 | |||||
| 162 | /* Check if this is an A or AAAA resource key */ | ||||
| 163 | |||||
| 164 | return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DNS_TYPE_A, DNS_TYPE_AAAA})/sizeof(int)] ; switch(key->type) { case DNS_TYPE_A: case DNS_TYPE_AAAA: _found = 1; break; default: break; } _found; }); | ||||
| 165 | } | ||||
| 166 | |||||
| 167 | bool_Bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key) { | ||||
| 168 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 168, __PRETTY_FUNCTION__); } while (0); | ||||
| 169 | |||||
| 170 | /* Check if this is a PTR resource key used in | ||||
| 171 | Service Instance Enumeration as described in RFC6763 p4.1. */ | ||||
| 172 | |||||
| 173 | if (key->type != DNS_TYPE_PTR) | ||||
| 174 | return false0; | ||||
| 175 | |||||
| 176 | return dns_name_endswith(dns_resource_key_name(key), "_tcp.local") || | ||||
| 177 | dns_name_endswith(dns_resource_key_name(key), "_udp.local"); | ||||
| 178 | } | ||||
| 179 | |||||
| 180 | int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) { | ||||
| 181 | int r; | ||||
| 182 | |||||
| 183 | if (a == b) | ||||
| 184 | return 1; | ||||
| 185 | |||||
| 186 | r = dns_name_equal(dns_resource_key_name(a), dns_resource_key_name(b)); | ||||
| 187 | if (r <= 0) | ||||
| 188 | return r; | ||||
| 189 | |||||
| 190 | if (a->class != b->class) | ||||
| 191 | return 0; | ||||
| 192 | |||||
| 193 | if (a->type != b->type) | ||||
| 194 | return 0; | ||||
| 195 | |||||
| 196 | return 1; | ||||
| 197 | } | ||||
| 198 | |||||
| 199 | int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) { | ||||
| 200 | int r; | ||||
| 201 | |||||
| 202 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 202, __PRETTY_FUNCTION__); } while (0); | ||||
| 203 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 203, __PRETTY_FUNCTION__); } while (0); | ||||
| 204 | |||||
| 205 | if (key == rr->key) | ||||
| 206 | return 1; | ||||
| 207 | |||||
| 208 | /* Checks if an rr matches the specified key. If a search | ||||
| 209 | * domain is specified, it will also be checked if the key | ||||
| 210 | * with the search domain suffixed might match the RR. */ | ||||
| 211 | |||||
| 212 | if (rr->key->class != key->class && key->class != DNS_CLASS_ANY) | ||||
| 213 | return 0; | ||||
| 214 | |||||
| 215 | if (rr->key->type != key->type && key->type != DNS_TYPE_ANY) | ||||
| 216 | return 0; | ||||
| 217 | |||||
| 218 | r = dns_name_equal(dns_resource_key_name(rr->key), dns_resource_key_name(key)); | ||||
| 219 | if (r != 0) | ||||
| 220 | return r; | ||||
| 221 | |||||
| 222 | if (search_domain) { | ||||
| 223 | _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0); | ||||
| 224 | |||||
| 225 | r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined); | ||||
| 226 | if (r < 0) | ||||
| 227 | return r; | ||||
| 228 | |||||
| 229 | return dns_name_equal(dns_resource_key_name(rr->key), joined); | ||||
| 230 | } | ||||
| 231 | |||||
| 232 | return 0; | ||||
| 233 | } | ||||
| 234 | |||||
| 235 | int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) { | ||||
| 236 | int r; | ||||
| 237 | |||||
| 238 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 238, __PRETTY_FUNCTION__); } while (0); | ||||
| 239 | assert(cname)do { if ((__builtin_expect(!!(!(cname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cname"), "../src/resolve/resolved-dns-rr.c" , 239, __PRETTY_FUNCTION__); } while (0); | ||||
| 240 | |||||
| 241 | if (cname->class != key->class && key->class != DNS_CLASS_ANY) | ||||
| 242 | return 0; | ||||
| 243 | |||||
| 244 | if (cname->type == DNS_TYPE_CNAME) | ||||
| 245 | r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname)); | ||||
| 246 | else if (cname->type == DNS_TYPE_DNAME) | ||||
| 247 | r = dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(cname)); | ||||
| 248 | else | ||||
| 249 | return 0; | ||||
| 250 | |||||
| 251 | if (r != 0) | ||||
| 252 | return r; | ||||
| 253 | |||||
| 254 | if (search_domain) { | ||||
| 255 | _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0); | ||||
| 256 | |||||
| 257 | r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined); | ||||
| 258 | if (r < 0) | ||||
| 259 | return r; | ||||
| 260 | |||||
| 261 | if (cname->type == DNS_TYPE_CNAME) | ||||
| 262 | return dns_name_equal(joined, dns_resource_key_name(cname)); | ||||
| 263 | else if (cname->type == DNS_TYPE_DNAME) | ||||
| 264 | return dns_name_endswith(joined, dns_resource_key_name(cname)); | ||||
| 265 | } | ||||
| 266 | |||||
| 267 | return 0; | ||||
| 268 | } | ||||
| 269 | |||||
| 270 | int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) { | ||||
| 271 | assert(soa)do { if ((__builtin_expect(!!(!(soa)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("soa"), "../src/resolve/resolved-dns-rr.c" , 271, __PRETTY_FUNCTION__); } while (0); | ||||
| 272 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-rr.c" , 272, __PRETTY_FUNCTION__); } while (0); | ||||
| 273 | |||||
| 274 | /* Checks whether 'soa' is a SOA record for the specified key. */ | ||||
| 275 | |||||
| 276 | if (soa->class != key->class) | ||||
| 277 | return 0; | ||||
| 278 | |||||
| 279 | if (soa->type != DNS_TYPE_SOA) | ||||
| 280 | return 0; | ||||
| 281 | |||||
| 282 | return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa)); | ||||
| 283 | } | ||||
| 284 | |||||
| 285 | static void dns_resource_key_hash_func(const void *i, struct siphash *state) { | ||||
| 286 | const DnsResourceKey *k = i; | ||||
| 287 | |||||
| 288 | assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("k"), "../src/resolve/resolved-dns-rr.c" , 288, __PRETTY_FUNCTION__); } while (0); | ||||
| 289 | |||||
| 290 | dns_name_hash_func(dns_resource_key_name(k), state); | ||||
| 291 | siphash24_compress(&k->class, sizeof(k->class), state); | ||||
| 292 | siphash24_compress(&k->type, sizeof(k->type), state); | ||||
| 293 | } | ||||
| 294 | |||||
| 295 | static int dns_resource_key_compare_func(const void *a, const void *b) { | ||||
| 296 | const DnsResourceKey *x = a, *y = b; | ||||
| 297 | int ret; | ||||
| 298 | |||||
| 299 | ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y)); | ||||
| 300 | if (ret != 0) | ||||
| 301 | return ret; | ||||
| 302 | |||||
| 303 | if (x->type < y->type) | ||||
| 304 | return -1; | ||||
| 305 | if (x->type > y->type) | ||||
| 306 | return 1; | ||||
| 307 | |||||
| 308 | if (x->class < y->class) | ||||
| 309 | return -1; | ||||
| 310 | if (x->class > y->class) | ||||
| 311 | return 1; | ||||
| 312 | |||||
| 313 | return 0; | ||||
| 314 | } | ||||
| 315 | |||||
| 316 | const struct hash_ops dns_resource_key_hash_ops = { | ||||
| 317 | .hash = dns_resource_key_hash_func, | ||||
| 318 | .compare = dns_resource_key_compare_func | ||||
| 319 | }; | ||||
| 320 | |||||
| 321 | char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) { | ||||
| 322 | const char *c, *t; | ||||
| 323 | char *ans = buf; | ||||
| 324 | |||||
| 325 | /* If we cannot convert the CLASS/TYPE into a known string, | ||||
| 326 | use the format recommended by RFC 3597, Section 5. */ | ||||
| 327 | |||||
| 328 | c = dns_class_to_string(key->class); | ||||
| 329 | t = dns_type_to_string(key->type); | ||||
| 330 | |||||
| 331 | snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u", | ||||
| 332 | dns_resource_key_name(key), | ||||
| 333 | strempty(c), c ? "" : "CLASS", c ? 0 : key->class, | ||||
| 334 | strempty(t), t ? "" : "TYPE", t ? 0 : key->type); | ||||
| 335 | |||||
| 336 | return ans; | ||||
| 337 | } | ||||
| 338 | |||||
| 339 | bool_Bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) { | ||||
| 340 | assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-rr.c" , 340, __PRETTY_FUNCTION__); } while (0); | ||||
| 341 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/resolve/resolved-dns-rr.c" , 341, __PRETTY_FUNCTION__); } while (0); | ||||
| 342 | |||||
| 343 | /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do | ||||
| 344 | * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come | ||||
| 345 | * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same | ||||
| 346 | * superficial data. */ | ||||
| 347 | |||||
| 348 | if (!*a) | ||||
| 349 | return false0; | ||||
| 350 | if (!*b) | ||||
| 351 | return false0; | ||||
| 352 | |||||
| 353 | /* We refuse merging const keys */ | ||||
| 354 | if ((*a)->n_ref == (unsigned) -1) | ||||
| 355 | return false0; | ||||
| 356 | if ((*b)->n_ref == (unsigned) -1) | ||||
| 357 | return false0; | ||||
| 358 | |||||
| 359 | /* Already the same? */ | ||||
| 360 | if (*a == *b) | ||||
| 361 | return true1; | ||||
| 362 | |||||
| 363 | /* Are they really identical? */ | ||||
| 364 | if (dns_resource_key_equal(*a, *b) <= 0) | ||||
| 365 | return false0; | ||||
| 366 | |||||
| 367 | /* Keep the one which already has more references. */ | ||||
| 368 | if ((*a)->n_ref > (*b)->n_ref) { | ||||
| 369 | dns_resource_key_unref(*b); | ||||
| 370 | *b = dns_resource_key_ref(*a); | ||||
| 371 | } else { | ||||
| 372 | dns_resource_key_unref(*a); | ||||
| 373 | *a = dns_resource_key_ref(*b); | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | return true1; | ||||
| 377 | } | ||||
| 378 | |||||
| 379 | DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { | ||||
| 380 | DnsResourceRecord *rr; | ||||
| 381 | |||||
| 382 | rr = new0(DnsResourceRecord, 1)((DnsResourceRecord*) calloc((1), sizeof(DnsResourceRecord))); | ||||
| 383 | if (!rr) | ||||
| 384 | return NULL((void*)0); | ||||
| 385 | |||||
| 386 | rr->n_ref = 1; | ||||
| 387 | rr->key = dns_resource_key_ref(key); | ||||
| 388 | rr->expiry = USEC_INFINITY((usec_t) -1); | ||||
| 389 | rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1; | ||||
| 390 | |||||
| 391 | return rr; | ||||
| 392 | } | ||||
| 393 | |||||
| 394 | DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) { | ||||
| 395 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | ||||
| 396 | |||||
| 397 | key = dns_resource_key_new(class, type, name); | ||||
| 398 | if (!key) | ||||
| 399 | return NULL((void*)0); | ||||
| 400 | |||||
| 401 | return dns_resource_record_new(key); | ||||
| 402 | } | ||||
| 403 | |||||
| 404 | DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) { | ||||
| 405 | if (!rr) | ||||
| 406 | return NULL((void*)0); | ||||
| 407 | |||||
| 408 | assert(rr->n_ref > 0)do { if ((__builtin_expect(!!(!(rr->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr->n_ref > 0"), "../src/resolve/resolved-dns-rr.c" , 408, __PRETTY_FUNCTION__); } while (0); | ||||
| 409 | rr->n_ref++; | ||||
| 410 | |||||
| 411 | return rr; | ||||
| 412 | } | ||||
| 413 | |||||
| 414 | DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { | ||||
| 415 | if (!rr) | ||||
| 416 | return NULL((void*)0); | ||||
| 417 | |||||
| 418 | assert(rr->n_ref > 0)do { if ((__builtin_expect(!!(!(rr->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr->n_ref > 0"), "../src/resolve/resolved-dns-rr.c" , 418, __PRETTY_FUNCTION__); } while (0); | ||||
| 419 | |||||
| 420 | if (rr->n_ref > 1) { | ||||
| 421 | rr->n_ref--; | ||||
| 422 | return NULL((void*)0); | ||||
| 423 | } | ||||
| 424 | |||||
| 425 | if (rr->key) { | ||||
| 426 | switch(rr->key->type) { | ||||
| 427 | |||||
| 428 | case DNS_TYPE_SRV: | ||||
| 429 | free(rr->srv.name); | ||||
| 430 | break; | ||||
| 431 | |||||
| 432 | case DNS_TYPE_PTR: | ||||
| 433 | case DNS_TYPE_NS: | ||||
| 434 | case DNS_TYPE_CNAME: | ||||
| 435 | case DNS_TYPE_DNAME: | ||||
| 436 | free(rr->ptr.name); | ||||
| 437 | break; | ||||
| 438 | |||||
| 439 | case DNS_TYPE_HINFO: | ||||
| 440 | free(rr->hinfo.cpu); | ||||
| 441 | free(rr->hinfo.os); | ||||
| 442 | break; | ||||
| 443 | |||||
| 444 | case DNS_TYPE_TXT: | ||||
| 445 | case DNS_TYPE_SPF: | ||||
| 446 | dns_txt_item_free_all(rr->txt.items); | ||||
| 447 | break; | ||||
| 448 | |||||
| 449 | case DNS_TYPE_SOA: | ||||
| 450 | free(rr->soa.mname); | ||||
| 451 | free(rr->soa.rname); | ||||
| 452 | break; | ||||
| 453 | |||||
| 454 | case DNS_TYPE_MX: | ||||
| 455 | free(rr->mx.exchange); | ||||
| 456 | break; | ||||
| 457 | |||||
| 458 | case DNS_TYPE_DS: | ||||
| 459 | free(rr->ds.digest); | ||||
| 460 | break; | ||||
| 461 | |||||
| 462 | case DNS_TYPE_SSHFP: | ||||
| 463 | free(rr->sshfp.fingerprint); | ||||
| 464 | break; | ||||
| 465 | |||||
| 466 | case DNS_TYPE_DNSKEY: | ||||
| 467 | free(rr->dnskey.key); | ||||
| 468 | break; | ||||
| 469 | |||||
| 470 | case DNS_TYPE_RRSIG: | ||||
| 471 | free(rr->rrsig.signer); | ||||
| 472 | free(rr->rrsig.signature); | ||||
| 473 | break; | ||||
| 474 | |||||
| 475 | case DNS_TYPE_NSEC: | ||||
| 476 | free(rr->nsec.next_domain_name); | ||||
| 477 | bitmap_free(rr->nsec.types); | ||||
| 478 | break; | ||||
| 479 | |||||
| 480 | case DNS_TYPE_NSEC3: | ||||
| 481 | free(rr->nsec3.next_hashed_name); | ||||
| 482 | free(rr->nsec3.salt); | ||||
| 483 | bitmap_free(rr->nsec3.types); | ||||
| 484 | break; | ||||
| 485 | |||||
| 486 | case DNS_TYPE_LOC: | ||||
| 487 | case DNS_TYPE_A: | ||||
| 488 | case DNS_TYPE_AAAA: | ||||
| 489 | break; | ||||
| 490 | |||||
| 491 | case DNS_TYPE_TLSA: | ||||
| 492 | free(rr->tlsa.data); | ||||
| 493 | break; | ||||
| 494 | |||||
| 495 | case DNS_TYPE_CAA: | ||||
| 496 | free(rr->caa.tag); | ||||
| 497 | free(rr->caa.value); | ||||
| 498 | break; | ||||
| 499 | |||||
| 500 | case DNS_TYPE_OPENPGPKEY: | ||||
| 501 | default: | ||||
| 502 | if (!rr->unparseable) | ||||
| 503 | free(rr->generic.data); | ||||
| 504 | } | ||||
| 505 | |||||
| 506 | if (rr->unparseable) | ||||
| 507 | free(rr->generic.data); | ||||
| 508 | |||||
| 509 | free(rr->wire_format); | ||||
| 510 | dns_resource_key_unref(rr->key); | ||||
| 511 | } | ||||
| 512 | |||||
| 513 | free(rr->to_string); | ||||
| 514 | return mfree(rr); | ||||
| 515 | } | ||||
| 516 | |||||
| 517 | int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) { | ||||
| 518 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | ||||
| 519 | _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *rr = NULL((void*)0); | ||||
| 520 | _cleanup_free___attribute__((cleanup(freep))) char *ptr = NULL((void*)0); | ||||
| 521 | int r; | ||||
| 522 | |||||
| 523 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-rr.c" , 523, __PRETTY_FUNCTION__); } while (0); | ||||
| 524 | assert(address)do { if ((__builtin_expect(!!(!(address)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("address"), "../src/resolve/resolved-dns-rr.c" , 524, __PRETTY_FUNCTION__); } while (0); | ||||
| 525 | assert(hostname)do { if ((__builtin_expect(!!(!(hostname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("hostname"), "../src/resolve/resolved-dns-rr.c" , 525, __PRETTY_FUNCTION__); } while (0); | ||||
| 526 | |||||
| 527 | r = dns_name_reverse(family, address, &ptr); | ||||
| 528 | if (r < 0) | ||||
| 529 | return r; | ||||
| 530 | |||||
| 531 | key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr); | ||||
| 532 | if (!key) | ||||
| 533 | return -ENOMEM12; | ||||
| 534 | |||||
| 535 | ptr = NULL((void*)0); | ||||
| 536 | |||||
| 537 | rr = dns_resource_record_new(key); | ||||
| 538 | if (!rr) | ||||
| 539 | return -ENOMEM12; | ||||
| 540 | |||||
| 541 | rr->ptr.name = strdup(hostname); | ||||
| 542 | if (!rr->ptr.name) | ||||
| 543 | return -ENOMEM12; | ||||
| 544 | |||||
| 545 | *ret = TAKE_PTR(rr)({ typeof(rr) _ptr_ = (rr); (rr) = ((void*)0); _ptr_; }); | ||||
| 546 | |||||
| 547 | return 0; | ||||
| 548 | } | ||||
| 549 | |||||
| 550 | int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) { | ||||
| 551 | DnsResourceRecord *rr; | ||||
| 552 | |||||
| 553 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-rr.c" , 553, __PRETTY_FUNCTION__); } while (0); | ||||
| 554 | assert(address)do { if ((__builtin_expect(!!(!(address)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("address"), "../src/resolve/resolved-dns-rr.c" , 554, __PRETTY_FUNCTION__); } while (0); | ||||
| 555 | assert(family)do { if ((__builtin_expect(!!(!(family)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("family"), "../src/resolve/resolved-dns-rr.c" , 555, __PRETTY_FUNCTION__); } while (0); | ||||
| 556 | |||||
| 557 | if (family == AF_INET2) { | ||||
| 558 | |||||
| 559 | rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name); | ||||
| 560 | if (!rr) | ||||
| 561 | return -ENOMEM12; | ||||
| 562 | |||||
| 563 | rr->a.in_addr = address->in; | ||||
| 564 | |||||
| 565 | } else if (family == AF_INET610) { | ||||
| 566 | |||||
| 567 | rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name); | ||||
| 568 | if (!rr) | ||||
| 569 | return -ENOMEM12; | ||||
| 570 | |||||
| 571 | rr->aaaa.in6_addr = address->in6; | ||||
| 572 | } else | ||||
| 573 | return -EAFNOSUPPORT97; | ||||
| 574 | |||||
| 575 | *ret = rr; | ||||
| 576 | |||||
| 577 | return 0; | ||||
| 578 | } | ||||
| 579 | |||||
| 580 | #define FIELD_EQUAL(a, b, field)((a).field_size == (b).field_size && memcmp((a).field , (b).field, (a).field_size) == 0) \ | ||||
| 581 | ((a).field ## _size == (b).field ## _size && \ | ||||
| 582 | memcmp((a).field, (b).field, (a).field ## _size) == 0) | ||||
| 583 | |||||
| 584 | int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) { | ||||
| 585 | int r; | ||||
| 586 | |||||
| 587 | assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-rr.c" , 587, __PRETTY_FUNCTION__); } while (0); | ||||
| 588 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/resolve/resolved-dns-rr.c" , 588, __PRETTY_FUNCTION__); } while (0); | ||||
| 589 | |||||
| 590 | if (a == b) | ||||
| 591 | return 1; | ||||
| 592 | |||||
| 593 | r = dns_resource_key_equal(a->key, b->key); | ||||
| 594 | if (r <= 0) | ||||
| 595 | return r; | ||||
| 596 | |||||
| 597 | if (a->unparseable != b->unparseable) | ||||
| 598 | return 0; | ||||
| 599 | |||||
| 600 | switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) { | ||||
| 601 | |||||
| 602 | case DNS_TYPE_SRV: | ||||
| 603 | r = dns_name_equal(a->srv.name, b->srv.name); | ||||
| 604 | if (r <= 0) | ||||
| 605 | return r; | ||||
| 606 | |||||
| 607 | return a->srv.priority == b->srv.priority && | ||||
| 608 | a->srv.weight == b->srv.weight && | ||||
| 609 | a->srv.port == b->srv.port; | ||||
| 610 | |||||
| 611 | case DNS_TYPE_PTR: | ||||
| 612 | case DNS_TYPE_NS: | ||||
| 613 | case DNS_TYPE_CNAME: | ||||
| 614 | case DNS_TYPE_DNAME: | ||||
| 615 | return dns_name_equal(a->ptr.name, b->ptr.name); | ||||
| 616 | |||||
| 617 | case DNS_TYPE_HINFO: | ||||
| 618 | return strcaseeq(a->hinfo.cpu, b->hinfo.cpu)(strcasecmp((a->hinfo.cpu),(b->hinfo.cpu)) == 0) && | ||||
| 619 | strcaseeq(a->hinfo.os, b->hinfo.os)(strcasecmp((a->hinfo.os),(b->hinfo.os)) == 0); | ||||
| 620 | |||||
| 621 | case DNS_TYPE_SPF: /* exactly the same as TXT */ | ||||
| 622 | case DNS_TYPE_TXT: | ||||
| 623 | return dns_txt_item_equal(a->txt.items, b->txt.items); | ||||
| 624 | |||||
| 625 | case DNS_TYPE_A: | ||||
| 626 | return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0; | ||||
| 627 | |||||
| 628 | case DNS_TYPE_AAAA: | ||||
| 629 | return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0; | ||||
| 630 | |||||
| 631 | case DNS_TYPE_SOA: | ||||
| 632 | r = dns_name_equal(a->soa.mname, b->soa.mname); | ||||
| 633 | if (r <= 0) | ||||
| 634 | return r; | ||||
| 635 | r = dns_name_equal(a->soa.rname, b->soa.rname); | ||||
| 636 | if (r <= 0) | ||||
| 637 | return r; | ||||
| 638 | |||||
| 639 | return a->soa.serial == b->soa.serial && | ||||
| 640 | a->soa.refresh == b->soa.refresh && | ||||
| 641 | a->soa.retry == b->soa.retry && | ||||
| 642 | a->soa.expire == b->soa.expire && | ||||
| 643 | a->soa.minimum == b->soa.minimum; | ||||
| 644 | |||||
| 645 | case DNS_TYPE_MX: | ||||
| 646 | if (a->mx.priority != b->mx.priority) | ||||
| 647 | return 0; | ||||
| 648 | |||||
| 649 | return dns_name_equal(a->mx.exchange, b->mx.exchange); | ||||
| 650 | |||||
| 651 | case DNS_TYPE_LOC: | ||||
| 652 | assert(a->loc.version == b->loc.version)do { if ((__builtin_expect(!!(!(a->loc.version == b->loc .version)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("a->loc.version == b->loc.version" ), "../src/resolve/resolved-dns-rr.c", 652, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 653 | |||||
| 654 | return a->loc.size == b->loc.size && | ||||
| 655 | a->loc.horiz_pre == b->loc.horiz_pre && | ||||
| 656 | a->loc.vert_pre == b->loc.vert_pre && | ||||
| 657 | a->loc.latitude == b->loc.latitude && | ||||
| 658 | a->loc.longitude == b->loc.longitude && | ||||
| 659 | a->loc.altitude == b->loc.altitude; | ||||
| 660 | |||||
| 661 | case DNS_TYPE_DS: | ||||
| 662 | return a->ds.key_tag == b->ds.key_tag && | ||||
| 663 | a->ds.algorithm == b->ds.algorithm && | ||||
| 664 | a->ds.digest_type == b->ds.digest_type && | ||||
| 665 | FIELD_EQUAL(a->ds, b->ds, digest)((a->ds).digest_size == (b->ds).digest_size && memcmp ((a->ds).digest, (b->ds).digest, (a->ds).digest_size ) == 0); | ||||
| 666 | |||||
| 667 | case DNS_TYPE_SSHFP: | ||||
| 668 | return a->sshfp.algorithm == b->sshfp.algorithm && | ||||
| 669 | a->sshfp.fptype == b->sshfp.fptype && | ||||
| 670 | FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint)((a->sshfp).fingerprint_size == (b->sshfp).fingerprint_size && memcmp((a->sshfp).fingerprint, (b->sshfp).fingerprint , (a->sshfp).fingerprint_size) == 0); | ||||
| 671 | |||||
| 672 | case DNS_TYPE_DNSKEY: | ||||
| 673 | return a->dnskey.flags == b->dnskey.flags && | ||||
| 674 | a->dnskey.protocol == b->dnskey.protocol && | ||||
| 675 | a->dnskey.algorithm == b->dnskey.algorithm && | ||||
| 676 | FIELD_EQUAL(a->dnskey, b->dnskey, key)((a->dnskey).key_size == (b->dnskey).key_size && memcmp((a->dnskey).key, (b->dnskey).key, (a->dnskey ).key_size) == 0); | ||||
| 677 | |||||
| 678 | case DNS_TYPE_RRSIG: | ||||
| 679 | /* do the fast comparisons first */ | ||||
| 680 | return a->rrsig.type_covered == b->rrsig.type_covered && | ||||
| 681 | a->rrsig.algorithm == b->rrsig.algorithm && | ||||
| 682 | a->rrsig.labels == b->rrsig.labels && | ||||
| 683 | a->rrsig.original_ttl == b->rrsig.original_ttl && | ||||
| 684 | a->rrsig.expiration == b->rrsig.expiration && | ||||
| 685 | a->rrsig.inception == b->rrsig.inception && | ||||
| 686 | a->rrsig.key_tag == b->rrsig.key_tag && | ||||
| 687 | FIELD_EQUAL(a->rrsig, b->rrsig, signature)((a->rrsig).signature_size == (b->rrsig).signature_size && memcmp((a->rrsig).signature, (b->rrsig).signature , (a->rrsig).signature_size) == 0) && | ||||
| 688 | dns_name_equal(a->rrsig.signer, b->rrsig.signer); | ||||
| 689 | |||||
| 690 | case DNS_TYPE_NSEC: | ||||
| 691 | return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) && | ||||
| 692 | bitmap_equal(a->nsec.types, b->nsec.types); | ||||
| 693 | |||||
| 694 | case DNS_TYPE_NSEC3: | ||||
| 695 | return a->nsec3.algorithm == b->nsec3.algorithm && | ||||
| 696 | a->nsec3.flags == b->nsec3.flags && | ||||
| 697 | a->nsec3.iterations == b->nsec3.iterations && | ||||
| 698 | FIELD_EQUAL(a->nsec3, b->nsec3, salt)((a->nsec3).salt_size == (b->nsec3).salt_size && memcmp((a->nsec3).salt, (b->nsec3).salt, (a->nsec3) .salt_size) == 0) && | ||||
| 699 | FIELD_EQUAL(a->nsec3, b->nsec3, next_hashed_name)((a->nsec3).next_hashed_name_size == (b->nsec3).next_hashed_name_size && memcmp((a->nsec3).next_hashed_name, (b->nsec3 ).next_hashed_name, (a->nsec3).next_hashed_name_size) == 0 ) && | ||||
| 700 | bitmap_equal(a->nsec3.types, b->nsec3.types); | ||||
| 701 | |||||
| 702 | case DNS_TYPE_TLSA: | ||||
| 703 | return a->tlsa.cert_usage == b->tlsa.cert_usage && | ||||
| 704 | a->tlsa.selector == b->tlsa.selector && | ||||
| 705 | a->tlsa.matching_type == b->tlsa.matching_type && | ||||
| 706 | FIELD_EQUAL(a->tlsa, b->tlsa, data)((a->tlsa).data_size == (b->tlsa).data_size && memcmp ((a->tlsa).data, (b->tlsa).data, (a->tlsa).data_size ) == 0); | ||||
| 707 | |||||
| 708 | case DNS_TYPE_CAA: | ||||
| 709 | return a->caa.flags == b->caa.flags && | ||||
| 710 | streq(a->caa.tag, b->caa.tag)(strcmp((a->caa.tag),(b->caa.tag)) == 0) && | ||||
| 711 | FIELD_EQUAL(a->caa, b->caa, value)((a->caa).value_size == (b->caa).value_size && memcmp ((a->caa).value, (b->caa).value, (a->caa).value_size ) == 0); | ||||
| 712 | |||||
| 713 | case DNS_TYPE_OPENPGPKEY: | ||||
| 714 | default: | ||||
| 715 | return FIELD_EQUAL(a->generic, b->generic, data)((a->generic).data_size == (b->generic).data_size && memcmp((a->generic).data, (b->generic).data, (a->generic ).data_size) == 0); | ||||
| 716 | } | ||||
| 717 | } | ||||
| 718 | |||||
| 719 | static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude, | ||||
| 720 | uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) { | ||||
| 721 | char *s; | ||||
| 722 | char NS = latitude >= 1U<<31 ? 'N' : 'S'; | ||||
| 723 | char EW = longitude >= 1U<<31 ? 'E' : 'W'; | ||||
| 724 | |||||
| 725 | int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude); | ||||
| 726 | int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude); | ||||
| 727 | double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude); | ||||
| 728 | double siz = (size >> 4) * exp10((double) (size & 0xF)); | ||||
| 729 | double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF)); | ||||
| 730 | double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF)); | ||||
| 731 | |||||
| 732 | if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm", | ||||
| 733 | (lat / 60000 / 60), | ||||
| 734 | (lat / 60000) % 60, | ||||
| 735 | (lat % 60000) / 1000., | ||||
| 736 | NS, | ||||
| 737 | (lon / 60000 / 60), | ||||
| 738 | (lon / 60000) % 60, | ||||
| 739 | (lon % 60000) / 1000., | ||||
| 740 | EW, | ||||
| 741 | alt / 100., | ||||
| 742 | siz / 100., | ||||
| 743 | hor / 100., | ||||
| 744 | ver / 100.) < 0) | ||||
| 745 | return NULL((void*)0); | ||||
| 746 | |||||
| 747 | return s; | ||||
| 748 | } | ||||
| 749 | |||||
| 750 | static int format_timestamp_dns(char *buf, size_t l, time_t sec) { | ||||
| 751 | struct tm tm; | ||||
| 752 | |||||
| 753 | assert(buf)do { if ((__builtin_expect(!!(!(buf)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("buf"), "../src/resolve/resolved-dns-rr.c" , 753, __PRETTY_FUNCTION__); } while (0); | ||||
| 754 | assert(l > STRLEN("YYYYMMDDHHmmSS"))do { if ((__builtin_expect(!!(!(l > (sizeof("""YYYYMMDDHHmmSS" "") - 1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("l > STRLEN(\"YYYYMMDDHHmmSS\")" ), "../src/resolve/resolved-dns-rr.c", 754, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 755 | |||||
| 756 | if (!gmtime_r(&sec, &tm)) | ||||
| 757 | return -EINVAL22; | ||||
| 758 | |||||
| 759 | if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0) | ||||
| 760 | return -EINVAL22; | ||||
| 761 | |||||
| 762 | return 0; | ||||
| 763 | } | ||||
| 764 | |||||
| 765 | static char *format_types(Bitmap *types) { | ||||
| 766 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **strv = NULL((void*)0); | ||||
| 767 | _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0); | ||||
| 768 | Iterator i; | ||||
| 769 | unsigned type; | ||||
| 770 | int r; | ||||
| 771 | |||||
| 772 | BITMAP_FOREACH(type, types, i)for ((i).idx = 0; bitmap_iterate((types), &(i), (unsigned *)&(type)); ) { | ||||
| 773 | if (dns_type_to_string(type)) { | ||||
| 774 | r = strv_extend(&strv, dns_type_to_string(type)); | ||||
| 775 | if (r < 0) | ||||
| 776 | return NULL((void*)0); | ||||
| 777 | } else { | ||||
| 778 | char *t; | ||||
| 779 | |||||
| 780 | r = asprintf(&t, "TYPE%u", type); | ||||
| 781 | if (r < 0) | ||||
| 782 | return NULL((void*)0); | ||||
| 783 | |||||
| 784 | r = strv_consume(&strv, t); | ||||
| 785 | if (r < 0) | ||||
| 786 | return NULL((void*)0); | ||||
| 787 | } | ||||
| 788 | } | ||||
| 789 | |||||
| 790 | str = strv_join(strv, " "); | ||||
| 791 | if (!str) | ||||
| 792 | return NULL((void*)0); | ||||
| 793 | |||||
| 794 | return strjoin("( ", str, " )")strjoin_real(("( "), str, " )", ((void*)0)); | ||||
| 795 | } | ||||
| 796 | |||||
| 797 | static char *format_txt(DnsTxtItem *first) { | ||||
| 798 | DnsTxtItem *i; | ||||
| 799 | size_t c = 1; | ||||
| 800 | char *p, *s; | ||||
| 801 | |||||
| 802 | LIST_FOREACH(items, i, first)for ((i) = (first); (i); (i) = (i)->items_next) | ||||
| 803 | c += i->length * 4 + 3; | ||||
| 804 | |||||
| 805 | p = s = new(char, c)((char*) malloc_multiply(sizeof(char), (c))); | ||||
| 806 | if (!s) | ||||
| 807 | return NULL((void*)0); | ||||
| 808 | |||||
| 809 | LIST_FOREACH(items, i, first)for ((i) = (first); (i); (i) = (i)->items_next) { | ||||
| 810 | size_t j; | ||||
| 811 | |||||
| 812 | if (i
| ||||
| 813 | *(p++) = ' '; | ||||
| 814 | |||||
| 815 | *(p++) = '"'; | ||||
| |||||
| 816 | |||||
| 817 | for (j = 0; j < i->length; j++) { | ||||
| 818 | if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) { | ||||
| 819 | *(p++) = '\\'; | ||||
| 820 | *(p++) = '0' + (i->data[j] / 100); | ||||
| 821 | *(p++) = '0' + ((i->data[j] / 10) % 10); | ||||
| 822 | *(p++) = '0' + (i->data[j] % 10); | ||||
| 823 | } else | ||||
| 824 | *(p++) = i->data[j]; | ||||
| 825 | } | ||||
| 826 | |||||
| 827 | *(p++) = '"'; | ||||
| 828 | } | ||||
| 829 | |||||
| 830 | *p = 0; | ||||
| 831 | return s; | ||||
| 832 | } | ||||
| 833 | |||||
| 834 | const char *dns_resource_record_to_string(DnsResourceRecord *rr) { | ||||
| 835 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | ||||
| 836 | char *s, k[DNS_RESOURCE_KEY_STRING_MAX((sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof( uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof (uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t) > 8)])))) + (sizeof "CLASS" + (2+(sizeof(uint16_t) <= 1 ? 3 : sizeof(uint16_t) <= 2 ? 5 : sizeof(uint16_t) <= 4 ? 10 : sizeof(uint16_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint16_t ) > 8)])))) + 253 + 1)]; | ||||
| 837 | int r; | ||||
| 838 | |||||
| 839 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 839, __PRETTY_FUNCTION__); } while (0); | ||||
| |||||
| 840 | |||||
| 841 | if (rr->to_string) | ||||
| 842 | return rr->to_string; | ||||
| 843 | |||||
| 844 | dns_resource_key_to_string(rr->key, k, sizeof(k)); | ||||
| 845 | |||||
| 846 | switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { | ||||
| 847 | |||||
| 848 | case DNS_TYPE_SRV: | ||||
| 849 | r = asprintf(&s, "%s %u %u %u %s", | ||||
| 850 | k, | ||||
| 851 | rr->srv.priority, | ||||
| 852 | rr->srv.weight, | ||||
| 853 | rr->srv.port, | ||||
| 854 | strna(rr->srv.name)); | ||||
| 855 | if (r < 0) | ||||
| 856 | return NULL((void*)0); | ||||
| 857 | break; | ||||
| 858 | |||||
| 859 | case DNS_TYPE_PTR: | ||||
| 860 | case DNS_TYPE_NS: | ||||
| 861 | case DNS_TYPE_CNAME: | ||||
| 862 | case DNS_TYPE_DNAME: | ||||
| 863 | s = strjoin(k, " ", rr->ptr.name)strjoin_real((k), " ", rr->ptr.name, ((void*)0)); | ||||
| 864 | if (!s) | ||||
| 865 | return NULL((void*)0); | ||||
| 866 | |||||
| 867 | break; | ||||
| 868 | |||||
| 869 | case DNS_TYPE_HINFO: | ||||
| 870 | s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os)strjoin_real((k), " ", rr->hinfo.cpu, " ", rr->hinfo.os , ((void*)0)); | ||||
| 871 | if (!s) | ||||
| 872 | return NULL((void*)0); | ||||
| 873 | break; | ||||
| 874 | |||||
| 875 | case DNS_TYPE_SPF: /* exactly the same as TXT */ | ||||
| 876 | case DNS_TYPE_TXT: | ||||
| 877 | t = format_txt(rr->txt.items); | ||||
| 878 | if (!t) | ||||
| 879 | return NULL((void*)0); | ||||
| 880 | |||||
| 881 | s = strjoin(k, " ", t)strjoin_real((k), " ", t, ((void*)0)); | ||||
| 882 | if (!s) | ||||
| 883 | return NULL((void*)0); | ||||
| 884 | break; | ||||
| 885 | |||||
| 886 | case DNS_TYPE_A: { | ||||
| 887 | _cleanup_free___attribute__((cleanup(freep))) char *x = NULL((void*)0); | ||||
| 888 | |||||
| 889 | r = in_addr_to_string(AF_INET2, (const union in_addr_union*) &rr->a.in_addr, &x); | ||||
| 890 | if (r < 0) | ||||
| 891 | return NULL((void*)0); | ||||
| 892 | |||||
| 893 | s = strjoin(k, " ", x)strjoin_real((k), " ", x, ((void*)0)); | ||||
| 894 | if (!s) | ||||
| 895 | return NULL((void*)0); | ||||
| 896 | break; | ||||
| 897 | } | ||||
| 898 | |||||
| 899 | case DNS_TYPE_AAAA: | ||||
| 900 | r = in_addr_to_string(AF_INET610, (const union in_addr_union*) &rr->aaaa.in6_addr, &t); | ||||
| 901 | if (r < 0) | ||||
| 902 | return NULL((void*)0); | ||||
| 903 | |||||
| 904 | s = strjoin(k, " ", t)strjoin_real((k), " ", t, ((void*)0)); | ||||
| 905 | if (!s) | ||||
| 906 | return NULL((void*)0); | ||||
| 907 | break; | ||||
| 908 | |||||
| 909 | case DNS_TYPE_SOA: | ||||
| 910 | r = asprintf(&s, "%s %s %s %u %u %u %u %u", | ||||
| 911 | k, | ||||
| 912 | strna(rr->soa.mname), | ||||
| 913 | strna(rr->soa.rname), | ||||
| 914 | rr->soa.serial, | ||||
| 915 | rr->soa.refresh, | ||||
| 916 | rr->soa.retry, | ||||
| 917 | rr->soa.expire, | ||||
| 918 | rr->soa.minimum); | ||||
| 919 | if (r < 0) | ||||
| 920 | return NULL((void*)0); | ||||
| 921 | break; | ||||
| 922 | |||||
| 923 | case DNS_TYPE_MX: | ||||
| 924 | r = asprintf(&s, "%s %u %s", | ||||
| 925 | k, | ||||
| 926 | rr->mx.priority, | ||||
| 927 | rr->mx.exchange); | ||||
| 928 | if (r < 0) | ||||
| 929 | return NULL((void*)0); | ||||
| 930 | break; | ||||
| 931 | |||||
| 932 | case DNS_TYPE_LOC: | ||||
| 933 | assert(rr->loc.version == 0)do { if ((__builtin_expect(!!(!(rr->loc.version == 0)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("rr->loc.version == 0" ), "../src/resolve/resolved-dns-rr.c", 933, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 934 | |||||
| 935 | t = format_location(rr->loc.latitude, | ||||
| 936 | rr->loc.longitude, | ||||
| 937 | rr->loc.altitude, | ||||
| 938 | rr->loc.size, | ||||
| 939 | rr->loc.horiz_pre, | ||||
| 940 | rr->loc.vert_pre); | ||||
| 941 | if (!t) | ||||
| 942 | return NULL((void*)0); | ||||
| 943 | |||||
| 944 | s = strjoin(k, " ", t)strjoin_real((k), " ", t, ((void*)0)); | ||||
| 945 | if (!s) | ||||
| 946 | return NULL((void*)0); | ||||
| 947 | break; | ||||
| 948 | |||||
| 949 | case DNS_TYPE_DS: | ||||
| 950 | t = hexmem(rr->ds.digest, rr->ds.digest_size); | ||||
| 951 | if (!t) | ||||
| 952 | return NULL((void*)0); | ||||
| 953 | |||||
| 954 | r = asprintf(&s, "%s %u %u %u %s", | ||||
| 955 | k, | ||||
| 956 | rr->ds.key_tag, | ||||
| 957 | rr->ds.algorithm, | ||||
| 958 | rr->ds.digest_type, | ||||
| 959 | t); | ||||
| 960 | if (r < 0) | ||||
| 961 | return NULL((void*)0); | ||||
| 962 | break; | ||||
| 963 | |||||
| 964 | case DNS_TYPE_SSHFP: | ||||
| 965 | t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); | ||||
| 966 | if (!t) | ||||
| 967 | return NULL((void*)0); | ||||
| 968 | |||||
| 969 | r = asprintf(&s, "%s %u %u %s", | ||||
| 970 | k, | ||||
| 971 | rr->sshfp.algorithm, | ||||
| 972 | rr->sshfp.fptype, | ||||
| 973 | t); | ||||
| 974 | if (r < 0) | ||||
| 975 | return NULL((void*)0); | ||||
| 976 | break; | ||||
| 977 | |||||
| 978 | case DNS_TYPE_DNSKEY: { | ||||
| 979 | _cleanup_free___attribute__((cleanup(freep))) char *alg = NULL((void*)0); | ||||
| 980 | char *ss; | ||||
| 981 | int n; | ||||
| 982 | uint16_t key_tag; | ||||
| 983 | |||||
| 984 | key_tag = dnssec_keytag(rr, true1); | ||||
| 985 | |||||
| 986 | r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg); | ||||
| 987 | if (r < 0) | ||||
| 988 | return NULL((void*)0); | ||||
| 989 | |||||
| 990 | r = asprintf(&s, "%s %u %u %s %n", | ||||
| 991 | k, | ||||
| 992 | rr->dnskey.flags, | ||||
| 993 | rr->dnskey.protocol, | ||||
| 994 | alg, | ||||
| 995 | &n); | ||||
| 996 | if (r < 0) | ||||
| 997 | return NULL((void*)0); | ||||
| 998 | |||||
| 999 | r = base64_append(&s, n, | ||||
| 1000 | rr->dnskey.key, rr->dnskey.key_size, | ||||
| 1001 | 8, columns()); | ||||
| 1002 | if (r < 0) | ||||
| 1003 | return NULL((void*)0); | ||||
| 1004 | |||||
| 1005 | r = asprintf(&ss, "%s\n" | ||||
| 1006 | " -- Flags:%s%s%s\n" | ||||
| 1007 | " -- Key tag: %u", | ||||
| 1008 | s, | ||||
| 1009 | rr->dnskey.flags & DNSKEY_FLAG_SEP(1 << 0) ? " SEP" : "", | ||||
| 1010 | rr->dnskey.flags & DNSKEY_FLAG_REVOKE(1 << 7) ? " REVOKE" : "", | ||||
| 1011 | rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY(1 << 8) ? " ZONE_KEY" : "", | ||||
| 1012 | key_tag); | ||||
| 1013 | if (r < 0) | ||||
| 1014 | return NULL((void*)0); | ||||
| 1015 | free(s); | ||||
| 1016 | s = ss; | ||||
| 1017 | |||||
| 1018 | break; | ||||
| 1019 | } | ||||
| 1020 | |||||
| 1021 | case DNS_TYPE_RRSIG: { | ||||
| 1022 | _cleanup_free___attribute__((cleanup(freep))) char *alg = NULL((void*)0); | ||||
| 1023 | char expiration[STRLEN("YYYYMMDDHHmmSS")(sizeof("""YYYYMMDDHHmmSS""") - 1) + 1], inception[STRLEN("YYYYMMDDHHmmSS")(sizeof("""YYYYMMDDHHmmSS""") - 1) + 1]; | ||||
| 1024 | const char *type; | ||||
| 1025 | int n; | ||||
| 1026 | |||||
| 1027 | type = dns_type_to_string(rr->rrsig.type_covered); | ||||
| 1028 | |||||
| 1029 | r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg); | ||||
| 1030 | if (r < 0) | ||||
| 1031 | return NULL((void*)0); | ||||
| 1032 | |||||
| 1033 | r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration); | ||||
| 1034 | if (r < 0) | ||||
| 1035 | return NULL((void*)0); | ||||
| 1036 | |||||
| 1037 | r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception); | ||||
| 1038 | if (r < 0) | ||||
| 1039 | return NULL((void*)0); | ||||
| 1040 | |||||
| 1041 | /* TYPE?? follows | ||||
| 1042 | * http://tools.ietf.org/html/rfc3597#section-5 */ | ||||
| 1043 | |||||
| 1044 | r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n", | ||||
| 1045 | k, | ||||
| 1046 | type ?: "TYPE", | ||||
| 1047 | type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered, | ||||
| 1048 | alg, | ||||
| 1049 | rr->rrsig.labels, | ||||
| 1050 | rr->rrsig.original_ttl, | ||||
| 1051 | expiration, | ||||
| 1052 | inception, | ||||
| 1053 | rr->rrsig.key_tag, | ||||
| 1054 | rr->rrsig.signer, | ||||
| 1055 | &n); | ||||
| 1056 | if (r < 0) | ||||
| 1057 | return NULL((void*)0); | ||||
| 1058 | |||||
| 1059 | r = base64_append(&s, n, | ||||
| 1060 | rr->rrsig.signature, rr->rrsig.signature_size, | ||||
| 1061 | 8, columns()); | ||||
| 1062 | if (r < 0) | ||||
| 1063 | return NULL((void*)0); | ||||
| 1064 | |||||
| 1065 | break; | ||||
| 1066 | } | ||||
| 1067 | |||||
| 1068 | case DNS_TYPE_NSEC: | ||||
| 1069 | t = format_types(rr->nsec.types); | ||||
| 1070 | if (!t) | ||||
| 1071 | return NULL((void*)0); | ||||
| 1072 | |||||
| 1073 | r = asprintf(&s, "%s %s %s", | ||||
| 1074 | k, | ||||
| 1075 | rr->nsec.next_domain_name, | ||||
| 1076 | t); | ||||
| 1077 | if (r < 0) | ||||
| 1078 | return NULL((void*)0); | ||||
| 1079 | break; | ||||
| 1080 | |||||
| 1081 | case DNS_TYPE_NSEC3: { | ||||
| 1082 | _cleanup_free___attribute__((cleanup(freep))) char *salt = NULL((void*)0), *hash = NULL((void*)0); | ||||
| 1083 | |||||
| 1084 | if (rr->nsec3.salt_size > 0) { | ||||
| 1085 | salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size); | ||||
| 1086 | if (!salt) | ||||
| 1087 | return NULL((void*)0); | ||||
| 1088 | } | ||||
| 1089 | |||||
| 1090 | hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false0); | ||||
| 1091 | if (!hash) | ||||
| 1092 | return NULL((void*)0); | ||||
| 1093 | |||||
| 1094 | t = format_types(rr->nsec3.types); | ||||
| 1095 | if (!t) | ||||
| 1096 | return NULL((void*)0); | ||||
| 1097 | |||||
| 1098 | r = asprintf(&s, "%s %"PRIu8"u"" %"PRIu8"u"" %"PRIu16"u"" %s %s %s", | ||||
| 1099 | k, | ||||
| 1100 | rr->nsec3.algorithm, | ||||
| 1101 | rr->nsec3.flags, | ||||
| 1102 | rr->nsec3.iterations, | ||||
| 1103 | rr->nsec3.salt_size > 0 ? salt : "-", | ||||
| 1104 | hash, | ||||
| 1105 | t); | ||||
| 1106 | if (r < 0) | ||||
| 1107 | return NULL((void*)0); | ||||
| 1108 | |||||
| 1109 | break; | ||||
| 1110 | } | ||||
| 1111 | |||||
| 1112 | case DNS_TYPE_TLSA: { | ||||
| 1113 | const char *cert_usage, *selector, *matching_type; | ||||
| 1114 | |||||
| 1115 | cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage); | ||||
| 1116 | selector = tlsa_selector_to_string(rr->tlsa.selector); | ||||
| 1117 | matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type); | ||||
| 1118 | |||||
| 1119 | t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); | ||||
| 1120 | if (!t) | ||||
| 1121 | return NULL((void*)0); | ||||
| 1122 | |||||
| 1123 | r = asprintf(&s, | ||||
| 1124 | "%s %u %u %u %s\n" | ||||
| 1125 | " -- Cert. usage: %s\n" | ||||
| 1126 | " -- Selector: %s\n" | ||||
| 1127 | " -- Matching type: %s", | ||||
| 1128 | k, | ||||
| 1129 | rr->tlsa.cert_usage, | ||||
| 1130 | rr->tlsa.selector, | ||||
| 1131 | rr->tlsa.matching_type, | ||||
| 1132 | t, | ||||
| 1133 | cert_usage, | ||||
| 1134 | selector, | ||||
| 1135 | matching_type); | ||||
| 1136 | if (r < 0) | ||||
| 1137 | return NULL((void*)0); | ||||
| 1138 | |||||
| 1139 | break; | ||||
| 1140 | } | ||||
| 1141 | |||||
| 1142 | case DNS_TYPE_CAA: { | ||||
| 1143 | _cleanup_free___attribute__((cleanup(freep))) char *value; | ||||
| 1144 | |||||
| 1145 | value = octescape(rr->caa.value, rr->caa.value_size); | ||||
| 1146 | if (!value) | ||||
| 1147 | return NULL((void*)0); | ||||
| 1148 | |||||
| 1149 | r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u", | ||||
| 1150 | k, | ||||
| 1151 | rr->caa.flags, | ||||
| 1152 | rr->caa.tag, | ||||
| 1153 | value, | ||||
| 1154 | rr->caa.flags ? "\n -- Flags:" : "", | ||||
| 1155 | rr->caa.flags & CAA_FLAG_CRITICAL(1u << 7) ? " critical" : "", | ||||
| 1156 | rr->caa.flags & ~CAA_FLAG_CRITICAL(1u << 7) ? " " : "", | ||||
| 1157 | rr->caa.flags & ~CAA_FLAG_CRITICAL(1u << 7)); | ||||
| 1158 | if (r < 0) | ||||
| 1159 | return NULL((void*)0); | ||||
| 1160 | |||||
| 1161 | break; | ||||
| 1162 | } | ||||
| 1163 | |||||
| 1164 | case DNS_TYPE_OPENPGPKEY: { | ||||
| 1165 | int n; | ||||
| 1166 | |||||
| 1167 | r = asprintf(&s, "%s %n", | ||||
| 1168 | k, | ||||
| 1169 | &n); | ||||
| 1170 | if (r < 0) | ||||
| 1171 | return NULL((void*)0); | ||||
| 1172 | |||||
| 1173 | r = base64_append(&s, n, | ||||
| 1174 | rr->generic.data, rr->generic.data_size, | ||||
| 1175 | 8, columns()); | ||||
| 1176 | if (r < 0) | ||||
| 1177 | return NULL((void*)0); | ||||
| 1178 | break; | ||||
| 1179 | } | ||||
| 1180 | |||||
| 1181 | default: | ||||
| 1182 | t = hexmem(rr->generic.data, rr->generic.data_size); | ||||
| 1183 | if (!t) | ||||
| 1184 | return NULL((void*)0); | ||||
| 1185 | |||||
| 1186 | /* Format as documented in RFC 3597, Section 5 */ | ||||
| 1187 | r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t); | ||||
| 1188 | if (r < 0) | ||||
| 1189 | return NULL((void*)0); | ||||
| 1190 | break; | ||||
| 1191 | } | ||||
| 1192 | |||||
| 1193 | rr->to_string = s; | ||||
| 1194 | return s; | ||||
| 1195 | } | ||||
| 1196 | |||||
| 1197 | ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) { | ||||
| 1198 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1198, __PRETTY_FUNCTION__); } while (0); | ||||
| 1199 | assert(out)do { if ((__builtin_expect(!!(!(out)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("out"), "../src/resolve/resolved-dns-rr.c" , 1199, __PRETTY_FUNCTION__); } while (0); | ||||
| 1200 | |||||
| 1201 | switch(rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { | ||||
| 1202 | case DNS_TYPE_SRV: | ||||
| 1203 | case DNS_TYPE_PTR: | ||||
| 1204 | case DNS_TYPE_NS: | ||||
| 1205 | case DNS_TYPE_CNAME: | ||||
| 1206 | case DNS_TYPE_DNAME: | ||||
| 1207 | case DNS_TYPE_HINFO: | ||||
| 1208 | case DNS_TYPE_SPF: | ||||
| 1209 | case DNS_TYPE_TXT: | ||||
| 1210 | case DNS_TYPE_A: | ||||
| 1211 | case DNS_TYPE_AAAA: | ||||
| 1212 | case DNS_TYPE_SOA: | ||||
| 1213 | case DNS_TYPE_MX: | ||||
| 1214 | case DNS_TYPE_LOC: | ||||
| 1215 | case DNS_TYPE_DS: | ||||
| 1216 | case DNS_TYPE_DNSKEY: | ||||
| 1217 | case DNS_TYPE_RRSIG: | ||||
| 1218 | case DNS_TYPE_NSEC: | ||||
| 1219 | case DNS_TYPE_NSEC3: | ||||
| 1220 | return -EINVAL22; | ||||
| 1221 | |||||
| 1222 | case DNS_TYPE_SSHFP: | ||||
| 1223 | *out = rr->sshfp.fingerprint; | ||||
| 1224 | return rr->sshfp.fingerprint_size; | ||||
| 1225 | |||||
| 1226 | case DNS_TYPE_TLSA: | ||||
| 1227 | *out = rr->tlsa.data; | ||||
| 1228 | return rr->tlsa.data_size; | ||||
| 1229 | |||||
| 1230 | case DNS_TYPE_OPENPGPKEY: | ||||
| 1231 | default: | ||||
| 1232 | *out = rr->generic.data; | ||||
| 1233 | return rr->generic.data_size; | ||||
| 1234 | } | ||||
| 1235 | } | ||||
| 1236 | |||||
| 1237 | int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool_Bool canonical) { | ||||
| 1238 | |||||
| 1239 | DnsPacket packet = { | ||||
| 1240 | .n_ref = 1, | ||||
| 1241 | .protocol = DNS_PROTOCOL_DNS, | ||||
| 1242 | .on_stack = true1, | ||||
| 1243 | .refuse_compression = true1, | ||||
| 1244 | .canonical_form = canonical, | ||||
| 1245 | }; | ||||
| 1246 | |||||
| 1247 | size_t start, rds; | ||||
| 1248 | int r; | ||||
| 1249 | |||||
| 1250 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1250, __PRETTY_FUNCTION__); } while (0); | ||||
| 1251 | |||||
| 1252 | /* Generates the RR in wire-format, optionally in the | ||||
| 1253 | * canonical form as discussed in the DNSSEC RFC 4034, Section | ||||
| 1254 | * 6.2. We allocate a throw-away DnsPacket object on the stack | ||||
| 1255 | * here, because we need some book-keeping for memory | ||||
| 1256 | * management, and can reuse the DnsPacket serializer, that | ||||
| 1257 | * can generate the canonical form, too, but also knows label | ||||
| 1258 | * compression and suchlike. */ | ||||
| 1259 | |||||
| 1260 | if (rr->wire_format && rr->wire_format_canonical == canonical) | ||||
| 1261 | return 0; | ||||
| 1262 | |||||
| 1263 | r = dns_packet_append_rr(&packet, rr, 0, &start, &rds); | ||||
| 1264 | if (r < 0) | ||||
| 1265 | return r; | ||||
| 1266 | |||||
| 1267 | assert(start == 0)do { if ((__builtin_expect(!!(!(start == 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("start == 0"), "../src/resolve/resolved-dns-rr.c" , 1267, __PRETTY_FUNCTION__); } while (0); | ||||
| 1268 | assert(packet._data)do { if ((__builtin_expect(!!(!(packet._data)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("packet._data"), "../src/resolve/resolved-dns-rr.c" , 1268, __PRETTY_FUNCTION__); } while (0); | ||||
| 1269 | |||||
| 1270 | free(rr->wire_format); | ||||
| 1271 | rr->wire_format = packet._data; | ||||
| 1272 | rr->wire_format_size = packet.size; | ||||
| 1273 | rr->wire_format_rdata_offset = rds; | ||||
| 1274 | rr->wire_format_canonical = canonical; | ||||
| 1275 | |||||
| 1276 | packet._data = NULL((void*)0); | ||||
| 1277 | dns_packet_unref(&packet); | ||||
| 1278 | |||||
| 1279 | return 0; | ||||
| 1280 | } | ||||
| 1281 | |||||
| 1282 | int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) { | ||||
| 1283 | const char *n; | ||||
| 1284 | int r; | ||||
| 1285 | |||||
| 1286 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1286, __PRETTY_FUNCTION__); } while (0); | ||||
| 1287 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-rr.c" , 1287, __PRETTY_FUNCTION__); } while (0); | ||||
| 1288 | |||||
| 1289 | /* Returns the RRset's signer, if it is known. */ | ||||
| 1290 | |||||
| 1291 | if (rr->n_skip_labels_signer == (unsigned) -1) | ||||
| 1292 | return -ENODATA61; | ||||
| 1293 | |||||
| 1294 | n = dns_resource_key_name(rr->key); | ||||
| 1295 | r = dns_name_skip(n, rr->n_skip_labels_signer, &n); | ||||
| 1296 | if (r < 0) | ||||
| 1297 | return r; | ||||
| 1298 | if (r == 0) | ||||
| 1299 | return -EINVAL22; | ||||
| 1300 | |||||
| 1301 | *ret = n; | ||||
| 1302 | return 0; | ||||
| 1303 | } | ||||
| 1304 | |||||
| 1305 | int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) { | ||||
| 1306 | const char *n; | ||||
| 1307 | int r; | ||||
| 1308 | |||||
| 1309 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1309, __PRETTY_FUNCTION__); } while (0); | ||||
| 1310 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-rr.c" , 1310, __PRETTY_FUNCTION__); } while (0); | ||||
| 1311 | |||||
| 1312 | /* Returns the RRset's synthesizing source, if it is known. */ | ||||
| 1313 | |||||
| 1314 | if (rr->n_skip_labels_source == (unsigned) -1) | ||||
| 1315 | return -ENODATA61; | ||||
| 1316 | |||||
| 1317 | n = dns_resource_key_name(rr->key); | ||||
| 1318 | r = dns_name_skip(n, rr->n_skip_labels_source, &n); | ||||
| 1319 | if (r < 0) | ||||
| 1320 | return r; | ||||
| 1321 | if (r == 0) | ||||
| 1322 | return -EINVAL22; | ||||
| 1323 | |||||
| 1324 | *ret = n; | ||||
| 1325 | return 0; | ||||
| 1326 | } | ||||
| 1327 | |||||
| 1328 | int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) { | ||||
| 1329 | const char *signer; | ||||
| 1330 | int r; | ||||
| 1331 | |||||
| 1332 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1332, __PRETTY_FUNCTION__); } while (0); | ||||
| 1333 | |||||
| 1334 | r = dns_resource_record_signer(rr, &signer); | ||||
| 1335 | if (r < 0) | ||||
| 1336 | return r; | ||||
| 1337 | |||||
| 1338 | return dns_name_equal(zone, signer); | ||||
| 1339 | } | ||||
| 1340 | |||||
| 1341 | int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { | ||||
| 1342 | int r; | ||||
| 1343 | |||||
| 1344 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1344, __PRETTY_FUNCTION__); } while (0); | ||||
| 1345 | |||||
| 1346 | /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */ | ||||
| 1347 | |||||
| 1348 | if (rr->n_skip_labels_source == (unsigned) -1) | ||||
| 1349 | return -ENODATA61; | ||||
| 1350 | |||||
| 1351 | if (rr->n_skip_labels_source == 0) | ||||
| 1352 | return 0; | ||||
| 1353 | |||||
| 1354 | if (rr->n_skip_labels_source > 1) | ||||
| 1355 | return 1; | ||||
| 1356 | |||||
| 1357 | r = dns_name_startswith(dns_resource_key_name(rr->key), "*"); | ||||
| 1358 | if (r < 0) | ||||
| 1359 | return r; | ||||
| 1360 | |||||
| 1361 | return !r; | ||||
| 1362 | } | ||||
| 1363 | |||||
| 1364 | void dns_resource_record_hash_func(const void *i, struct siphash *state) { | ||||
| 1365 | const DnsResourceRecord *rr = i; | ||||
| 1366 | |||||
| 1367 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1367, __PRETTY_FUNCTION__); } while (0); | ||||
| 1368 | |||||
| 1369 | dns_resource_key_hash_func(rr->key, state); | ||||
| 1370 | |||||
| 1371 | switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { | ||||
| 1372 | |||||
| 1373 | case DNS_TYPE_SRV: | ||||
| 1374 | siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state); | ||||
| 1375 | siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state); | ||||
| 1376 | siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state); | ||||
| 1377 | dns_name_hash_func(rr->srv.name, state); | ||||
| 1378 | break; | ||||
| 1379 | |||||
| 1380 | case DNS_TYPE_PTR: | ||||
| 1381 | case DNS_TYPE_NS: | ||||
| 1382 | case DNS_TYPE_CNAME: | ||||
| 1383 | case DNS_TYPE_DNAME: | ||||
| 1384 | dns_name_hash_func(rr->ptr.name, state); | ||||
| 1385 | break; | ||||
| 1386 | |||||
| 1387 | case DNS_TYPE_HINFO: | ||||
| 1388 | string_hash_func(rr->hinfo.cpu, state); | ||||
| 1389 | string_hash_func(rr->hinfo.os, state); | ||||
| 1390 | break; | ||||
| 1391 | |||||
| 1392 | case DNS_TYPE_TXT: | ||||
| 1393 | case DNS_TYPE_SPF: { | ||||
| 1394 | DnsTxtItem *j; | ||||
| 1395 | |||||
| 1396 | LIST_FOREACH(items, j, rr->txt.items)for ((j) = (rr->txt.items); (j); (j) = (j)->items_next) { | ||||
| 1397 | siphash24_compress(j->data, j->length, state); | ||||
| 1398 | |||||
| 1399 | /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab" | ||||
| 1400 | * followed by "". */ | ||||
| 1401 | siphash24_compress_byte(0, state)siphash24_compress((const uint8_t[]) { (0) }, 1, (state)); | ||||
| 1402 | } | ||||
| 1403 | break; | ||||
| 1404 | } | ||||
| 1405 | |||||
| 1406 | case DNS_TYPE_A: | ||||
| 1407 | siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state); | ||||
| 1408 | break; | ||||
| 1409 | |||||
| 1410 | case DNS_TYPE_AAAA: | ||||
| 1411 | siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state); | ||||
| 1412 | break; | ||||
| 1413 | |||||
| 1414 | case DNS_TYPE_SOA: | ||||
| 1415 | dns_name_hash_func(rr->soa.mname, state); | ||||
| 1416 | dns_name_hash_func(rr->soa.rname, state); | ||||
| 1417 | siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state); | ||||
| 1418 | siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state); | ||||
| 1419 | siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state); | ||||
| 1420 | siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state); | ||||
| 1421 | siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state); | ||||
| 1422 | break; | ||||
| 1423 | |||||
| 1424 | case DNS_TYPE_MX: | ||||
| 1425 | siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state); | ||||
| 1426 | dns_name_hash_func(rr->mx.exchange, state); | ||||
| 1427 | break; | ||||
| 1428 | |||||
| 1429 | case DNS_TYPE_LOC: | ||||
| 1430 | siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state); | ||||
| 1431 | siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state); | ||||
| 1432 | siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state); | ||||
| 1433 | siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state); | ||||
| 1434 | siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state); | ||||
| 1435 | siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state); | ||||
| 1436 | siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state); | ||||
| 1437 | break; | ||||
| 1438 | |||||
| 1439 | case DNS_TYPE_SSHFP: | ||||
| 1440 | siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state); | ||||
| 1441 | siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state); | ||||
| 1442 | siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state); | ||||
| 1443 | break; | ||||
| 1444 | |||||
| 1445 | case DNS_TYPE_DNSKEY: | ||||
| 1446 | siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state); | ||||
| 1447 | siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state); | ||||
| 1448 | siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state); | ||||
| 1449 | siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state); | ||||
| 1450 | break; | ||||
| 1451 | |||||
| 1452 | case DNS_TYPE_RRSIG: | ||||
| 1453 | siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state); | ||||
| 1454 | siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state); | ||||
| 1455 | siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state); | ||||
| 1456 | siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state); | ||||
| 1457 | siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state); | ||||
| 1458 | siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state); | ||||
| 1459 | siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state); | ||||
| 1460 | dns_name_hash_func(rr->rrsig.signer, state); | ||||
| 1461 | siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state); | ||||
| 1462 | break; | ||||
| 1463 | |||||
| 1464 | case DNS_TYPE_NSEC: | ||||
| 1465 | dns_name_hash_func(rr->nsec.next_domain_name, state); | ||||
| 1466 | /* FIXME: we leave out the type bitmap here. Hash | ||||
| 1467 | * would be better if we'd take it into account | ||||
| 1468 | * too. */ | ||||
| 1469 | break; | ||||
| 1470 | |||||
| 1471 | case DNS_TYPE_DS: | ||||
| 1472 | siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state); | ||||
| 1473 | siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state); | ||||
| 1474 | siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state); | ||||
| 1475 | siphash24_compress(rr->ds.digest, rr->ds.digest_size, state); | ||||
| 1476 | break; | ||||
| 1477 | |||||
| 1478 | case DNS_TYPE_NSEC3: | ||||
| 1479 | siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state); | ||||
| 1480 | siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state); | ||||
| 1481 | siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state); | ||||
| 1482 | siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state); | ||||
| 1483 | siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state); | ||||
| 1484 | /* FIXME: We leave the bitmaps out */ | ||||
| 1485 | break; | ||||
| 1486 | |||||
| 1487 | case DNS_TYPE_TLSA: | ||||
| 1488 | siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state); | ||||
| 1489 | siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state); | ||||
| 1490 | siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state); | ||||
| 1491 | siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state); | ||||
| 1492 | break; | ||||
| 1493 | |||||
| 1494 | case DNS_TYPE_CAA: | ||||
| 1495 | siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state); | ||||
| 1496 | string_hash_func(rr->caa.tag, state); | ||||
| 1497 | siphash24_compress(rr->caa.value, rr->caa.value_size, state); | ||||
| 1498 | break; | ||||
| 1499 | |||||
| 1500 | case DNS_TYPE_OPENPGPKEY: | ||||
| 1501 | default: | ||||
| 1502 | siphash24_compress(rr->generic.data, rr->generic.data_size, state); | ||||
| 1503 | break; | ||||
| 1504 | } | ||||
| 1505 | } | ||||
| 1506 | |||||
| 1507 | static int dns_resource_record_compare_func(const void *a, const void *b) { | ||||
| 1508 | const DnsResourceRecord *x = a, *y = b; | ||||
| 1509 | int ret; | ||||
| 1510 | |||||
| 1511 | ret = dns_resource_key_compare_func(x->key, y->key); | ||||
| 1512 | if (ret != 0) | ||||
| 1513 | return ret; | ||||
| 1514 | |||||
| 1515 | if (dns_resource_record_equal(x, y)) | ||||
| 1516 | return 0; | ||||
| 1517 | |||||
| 1518 | /* This is a bit dirty, we don't implement proper ordering, but | ||||
| 1519 | * the hashtable doesn't need ordering anyway, hence we don't | ||||
| 1520 | * care. */ | ||||
| 1521 | return x < y ? -1 : 1; | ||||
| 1522 | } | ||||
| 1523 | |||||
| 1524 | const struct hash_ops dns_resource_record_hash_ops = { | ||||
| 1525 | .hash = dns_resource_record_hash_func, | ||||
| 1526 | .compare = dns_resource_record_compare_func, | ||||
| 1527 | }; | ||||
| 1528 | |||||
| 1529 | DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) { | ||||
| 1530 | _cleanup_(dns_resource_record_unrefp)__attribute__((cleanup(dns_resource_record_unrefp))) DnsResourceRecord *copy = NULL((void*)0); | ||||
| 1531 | DnsResourceRecord *t; | ||||
| 1532 | |||||
| 1533 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1533, __PRETTY_FUNCTION__); } while (0); | ||||
| 1534 | |||||
| 1535 | copy = dns_resource_record_new(rr->key); | ||||
| 1536 | if (!copy) | ||||
| 1537 | return NULL((void*)0); | ||||
| 1538 | |||||
| 1539 | copy->ttl = rr->ttl; | ||||
| 1540 | copy->expiry = rr->expiry; | ||||
| 1541 | copy->n_skip_labels_signer = rr->n_skip_labels_signer; | ||||
| 1542 | copy->n_skip_labels_source = rr->n_skip_labels_source; | ||||
| 1543 | copy->unparseable = rr->unparseable; | ||||
| 1544 | |||||
| 1545 | switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { | ||||
| 1546 | |||||
| 1547 | case DNS_TYPE_SRV: | ||||
| 1548 | copy->srv.priority = rr->srv.priority; | ||||
| 1549 | copy->srv.weight = rr->srv.weight; | ||||
| 1550 | copy->srv.port = rr->srv.port; | ||||
| 1551 | copy->srv.name = strdup(rr->srv.name); | ||||
| 1552 | if (!copy->srv.name) | ||||
| 1553 | return NULL((void*)0); | ||||
| 1554 | break; | ||||
| 1555 | |||||
| 1556 | case DNS_TYPE_PTR: | ||||
| 1557 | case DNS_TYPE_NS: | ||||
| 1558 | case DNS_TYPE_CNAME: | ||||
| 1559 | case DNS_TYPE_DNAME: | ||||
| 1560 | copy->ptr.name = strdup(rr->ptr.name); | ||||
| 1561 | if (!copy->ptr.name) | ||||
| 1562 | return NULL((void*)0); | ||||
| 1563 | break; | ||||
| 1564 | |||||
| 1565 | case DNS_TYPE_HINFO: | ||||
| 1566 | copy->hinfo.cpu = strdup(rr->hinfo.cpu); | ||||
| 1567 | if (!copy->hinfo.cpu) | ||||
| 1568 | return NULL((void*)0); | ||||
| 1569 | |||||
| 1570 | copy->hinfo.os = strdup(rr->hinfo.os); | ||||
| 1571 | if (!copy->hinfo.os) | ||||
| 1572 | return NULL((void*)0); | ||||
| 1573 | break; | ||||
| 1574 | |||||
| 1575 | case DNS_TYPE_TXT: | ||||
| 1576 | case DNS_TYPE_SPF: | ||||
| 1577 | copy->txt.items = dns_txt_item_copy(rr->txt.items); | ||||
| 1578 | if (!copy->txt.items) | ||||
| 1579 | return NULL((void*)0); | ||||
| 1580 | break; | ||||
| 1581 | |||||
| 1582 | case DNS_TYPE_A: | ||||
| 1583 | copy->a = rr->a; | ||||
| 1584 | break; | ||||
| 1585 | |||||
| 1586 | case DNS_TYPE_AAAA: | ||||
| 1587 | copy->aaaa = rr->aaaa; | ||||
| 1588 | break; | ||||
| 1589 | |||||
| 1590 | case DNS_TYPE_SOA: | ||||
| 1591 | copy->soa.mname = strdup(rr->soa.mname); | ||||
| 1592 | if (!copy->soa.mname) | ||||
| 1593 | return NULL((void*)0); | ||||
| 1594 | copy->soa.rname = strdup(rr->soa.rname); | ||||
| 1595 | if (!copy->soa.rname) | ||||
| 1596 | return NULL((void*)0); | ||||
| 1597 | copy->soa.serial = rr->soa.serial; | ||||
| 1598 | copy->soa.refresh = rr->soa.refresh; | ||||
| 1599 | copy->soa.retry = rr->soa.retry; | ||||
| 1600 | copy->soa.expire = rr->soa.expire; | ||||
| 1601 | copy->soa.minimum = rr->soa.minimum; | ||||
| 1602 | break; | ||||
| 1603 | |||||
| 1604 | case DNS_TYPE_MX: | ||||
| 1605 | copy->mx.priority = rr->mx.priority; | ||||
| 1606 | copy->mx.exchange = strdup(rr->mx.exchange); | ||||
| 1607 | if (!copy->mx.exchange) | ||||
| 1608 | return NULL((void*)0); | ||||
| 1609 | break; | ||||
| 1610 | |||||
| 1611 | case DNS_TYPE_LOC: | ||||
| 1612 | copy->loc = rr->loc; | ||||
| 1613 | break; | ||||
| 1614 | |||||
| 1615 | case DNS_TYPE_SSHFP: | ||||
| 1616 | copy->sshfp.algorithm = rr->sshfp.algorithm; | ||||
| 1617 | copy->sshfp.fptype = rr->sshfp.fptype; | ||||
| 1618 | copy->sshfp.fingerprint = memdup(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); | ||||
| 1619 | if (!copy->sshfp.fingerprint) | ||||
| 1620 | return NULL((void*)0); | ||||
| 1621 | copy->sshfp.fingerprint_size = rr->sshfp.fingerprint_size; | ||||
| 1622 | break; | ||||
| 1623 | |||||
| 1624 | case DNS_TYPE_DNSKEY: | ||||
| 1625 | copy->dnskey.flags = rr->dnskey.flags; | ||||
| 1626 | copy->dnskey.protocol = rr->dnskey.protocol; | ||||
| 1627 | copy->dnskey.algorithm = rr->dnskey.algorithm; | ||||
| 1628 | copy->dnskey.key = memdup(rr->dnskey.key, rr->dnskey.key_size); | ||||
| 1629 | if (!copy->dnskey.key) | ||||
| 1630 | return NULL((void*)0); | ||||
| 1631 | copy->dnskey.key_size = rr->dnskey.key_size; | ||||
| 1632 | break; | ||||
| 1633 | |||||
| 1634 | case DNS_TYPE_RRSIG: | ||||
| 1635 | copy->rrsig.type_covered = rr->rrsig.type_covered; | ||||
| 1636 | copy->rrsig.algorithm = rr->rrsig.algorithm; | ||||
| 1637 | copy->rrsig.labels = rr->rrsig.labels; | ||||
| 1638 | copy->rrsig.original_ttl = rr->rrsig.original_ttl; | ||||
| 1639 | copy->rrsig.expiration = rr->rrsig.expiration; | ||||
| 1640 | copy->rrsig.inception = rr->rrsig.inception; | ||||
| 1641 | copy->rrsig.key_tag = rr->rrsig.key_tag; | ||||
| 1642 | copy->rrsig.signer = strdup(rr->rrsig.signer); | ||||
| 1643 | if (!copy->rrsig.signer) | ||||
| 1644 | return NULL((void*)0); | ||||
| 1645 | copy->rrsig.signature = memdup(rr->rrsig.signature, rr->rrsig.signature_size); | ||||
| 1646 | if (!copy->rrsig.signature) | ||||
| 1647 | return NULL((void*)0); | ||||
| 1648 | copy->rrsig.signature_size = rr->rrsig.signature_size; | ||||
| 1649 | break; | ||||
| 1650 | |||||
| 1651 | case DNS_TYPE_NSEC: | ||||
| 1652 | copy->nsec.next_domain_name = strdup(rr->nsec.next_domain_name); | ||||
| 1653 | if (!copy->nsec.next_domain_name) | ||||
| 1654 | return NULL((void*)0); | ||||
| 1655 | copy->nsec.types = bitmap_copy(rr->nsec.types); | ||||
| 1656 | if (!copy->nsec.types) | ||||
| 1657 | return NULL((void*)0); | ||||
| 1658 | break; | ||||
| 1659 | |||||
| 1660 | case DNS_TYPE_DS: | ||||
| 1661 | copy->ds.key_tag = rr->ds.key_tag; | ||||
| 1662 | copy->ds.algorithm = rr->ds.algorithm; | ||||
| 1663 | copy->ds.digest_type = rr->ds.digest_type; | ||||
| 1664 | copy->ds.digest = memdup(rr->ds.digest, rr->ds.digest_size); | ||||
| 1665 | if (!copy->ds.digest) | ||||
| 1666 | return NULL((void*)0); | ||||
| 1667 | copy->ds.digest_size = rr->ds.digest_size; | ||||
| 1668 | break; | ||||
| 1669 | |||||
| 1670 | case DNS_TYPE_NSEC3: | ||||
| 1671 | copy->nsec3.algorithm = rr->nsec3.algorithm; | ||||
| 1672 | copy->nsec3.flags = rr->nsec3.flags; | ||||
| 1673 | copy->nsec3.iterations = rr->nsec3.iterations; | ||||
| 1674 | copy->nsec3.salt = memdup(rr->nsec3.salt, rr->nsec3.salt_size); | ||||
| 1675 | if (!copy->nsec3.salt) | ||||
| 1676 | return NULL((void*)0); | ||||
| 1677 | copy->nsec3.salt_size = rr->nsec3.salt_size; | ||||
| 1678 | copy->nsec3.next_hashed_name = memdup(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size); | ||||
| 1679 | if (!copy->nsec3.next_hashed_name_size) | ||||
| 1680 | return NULL((void*)0); | ||||
| 1681 | copy->nsec3.next_hashed_name_size = rr->nsec3.next_hashed_name_size; | ||||
| 1682 | copy->nsec3.types = bitmap_copy(rr->nsec3.types); | ||||
| 1683 | if (!copy->nsec3.types) | ||||
| 1684 | return NULL((void*)0); | ||||
| 1685 | break; | ||||
| 1686 | |||||
| 1687 | case DNS_TYPE_TLSA: | ||||
| 1688 | copy->tlsa.cert_usage = rr->tlsa.cert_usage; | ||||
| 1689 | copy->tlsa.selector = rr->tlsa.selector; | ||||
| 1690 | copy->tlsa.matching_type = rr->tlsa.matching_type; | ||||
| 1691 | copy->tlsa.data = memdup(rr->tlsa.data, rr->tlsa.data_size); | ||||
| 1692 | if (!copy->tlsa.data) | ||||
| 1693 | return NULL((void*)0); | ||||
| 1694 | copy->tlsa.data_size = rr->tlsa.data_size; | ||||
| 1695 | break; | ||||
| 1696 | |||||
| 1697 | case DNS_TYPE_CAA: | ||||
| 1698 | copy->caa.flags = rr->caa.flags; | ||||
| 1699 | copy->caa.tag = strdup(rr->caa.tag); | ||||
| 1700 | if (!copy->caa.tag) | ||||
| 1701 | return NULL((void*)0); | ||||
| 1702 | copy->caa.value = memdup(rr->caa.value, rr->caa.value_size); | ||||
| 1703 | if (!copy->caa.value) | ||||
| 1704 | return NULL((void*)0); | ||||
| 1705 | copy->caa.value_size = rr->caa.value_size; | ||||
| 1706 | break; | ||||
| 1707 | |||||
| 1708 | case DNS_TYPE_OPT: | ||||
| 1709 | default: | ||||
| 1710 | copy->generic.data = memdup(rr->generic.data, rr->generic.data_size); | ||||
| 1711 | if (!copy->generic.data) | ||||
| 1712 | return NULL((void*)0); | ||||
| 1713 | copy->generic.data_size = rr->generic.data_size; | ||||
| 1714 | break; | ||||
| 1715 | } | ||||
| 1716 | |||||
| 1717 | t = TAKE_PTR(copy)({ typeof(copy) _ptr_ = (copy); (copy) = ((void*)0); _ptr_; } ); | ||||
| 1718 | |||||
| 1719 | return t; | ||||
| 1720 | } | ||||
| 1721 | |||||
| 1722 | int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) { | ||||
| 1723 | DnsResourceRecord *old_rr, *new_rr; | ||||
| 1724 | uint32_t new_ttl; | ||||
| 1725 | |||||
| 1726 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-rr.c" , 1726, __PRETTY_FUNCTION__); } while (0); | ||||
| 1727 | old_rr = *rr; | ||||
| 1728 | |||||
| 1729 | if (old_rr->key->type == DNS_TYPE_OPT) | ||||
| 1730 | return -EINVAL22; | ||||
| 1731 | |||||
| 1732 | new_ttl = MIN(old_rr->ttl, max_ttl)__extension__ ({ const typeof((old_rr->ttl)) __unique_prefix_A21 = ((old_rr->ttl)); const typeof((max_ttl)) __unique_prefix_B22 = ((max_ttl)); __unique_prefix_A21 < __unique_prefix_B22 ? __unique_prefix_A21 : __unique_prefix_B22; }); | ||||
| 1733 | if (new_ttl == old_rr->ttl) | ||||
| 1734 | return 0; | ||||
| 1735 | |||||
| 1736 | if (old_rr->n_ref == 1) { | ||||
| 1737 | /* Patch in place */ | ||||
| 1738 | old_rr->ttl = new_ttl; | ||||
| 1739 | return 1; | ||||
| 1740 | } | ||||
| 1741 | |||||
| 1742 | new_rr = dns_resource_record_copy(old_rr); | ||||
| 1743 | if (!new_rr) | ||||
| 1744 | return -ENOMEM12; | ||||
| 1745 | |||||
| 1746 | new_rr->ttl = new_ttl; | ||||
| 1747 | |||||
| 1748 | dns_resource_record_unref(*rr); | ||||
| 1749 | *rr = new_rr; | ||||
| 1750 | |||||
| 1751 | return 1; | ||||
| 1752 | } | ||||
| 1753 | |||||
| 1754 | DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { | ||||
| 1755 | DnsTxtItem *n; | ||||
| 1756 | |||||
| 1757 | if (!i) | ||||
| 1758 | return NULL((void*)0); | ||||
| 1759 | |||||
| 1760 | n = i->items_next; | ||||
| 1761 | |||||
| 1762 | free(i); | ||||
| 1763 | return dns_txt_item_free_all(n); | ||||
| 1764 | } | ||||
| 1765 | |||||
| 1766 | bool_Bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) { | ||||
| 1767 | |||||
| 1768 | if (a == b) | ||||
| 1769 | return true1; | ||||
| 1770 | |||||
| 1771 | if (!a != !b) | ||||
| 1772 | return false0; | ||||
| 1773 | |||||
| 1774 | if (!a) | ||||
| 1775 | return true1; | ||||
| 1776 | |||||
| 1777 | if (a->length != b->length) | ||||
| 1778 | return false0; | ||||
| 1779 | |||||
| 1780 | if (memcmp(a->data, b->data, a->length) != 0) | ||||
| 1781 | return false0; | ||||
| 1782 | |||||
| 1783 | return dns_txt_item_equal(a->items_next, b->items_next); | ||||
| 1784 | } | ||||
| 1785 | |||||
| 1786 | DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) { | ||||
| 1787 | DnsTxtItem *i, *copy = NULL((void*)0), *end = NULL((void*)0); | ||||
| 1788 | |||||
| 1789 | LIST_FOREACH(items, i, first)for ((i) = (first); (i); (i) = (i)->items_next) { | ||||
| 1790 | DnsTxtItem *j; | ||||
| 1791 | |||||
| 1792 | j = memdup(i, offsetof(DnsTxtItem, data)__builtin_offsetof(DnsTxtItem, data) + i->length + 1); | ||||
| 1793 | if (!j) { | ||||
| 1794 | dns_txt_item_free_all(copy); | ||||
| 1795 | return NULL((void*)0); | ||||
| 1796 | } | ||||
| 1797 | |||||
| 1798 | LIST_INSERT_AFTER(items, copy, end, j)do { typeof(*(copy)) **_head = &(copy), *_a = (end), *_b = (j); do { if ((__builtin_expect(!!(!(_b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_b"), "../src/resolve/resolved-dns-rr.c" , 1798, __PRETTY_FUNCTION__); } while (0); if (!_a) { if ((_b ->items_next = *_head)) _b->items_next->items_prev = _b; _b->items_prev = ((void*)0); *_head = _b; } else { if ((_b->items_next = _a->items_next)) _b->items_next-> items_prev = _b; _b->items_prev = _a; _a->items_next = _b ; } } while (0); | ||||
| 1799 | end = j; | ||||
| 1800 | } | ||||
| 1801 | |||||
| 1802 | return copy; | ||||
| 1803 | } | ||||
| 1804 | |||||
| 1805 | int dns_txt_item_new_empty(DnsTxtItem **ret) { | ||||
| 1806 | DnsTxtItem *i; | ||||
| 1807 | |||||
| 1808 | /* RFC 6763, section 6.1 suggests to treat | ||||
| 1809 | * empty TXT RRs as equivalent to a TXT record | ||||
| 1810 | * with a single empty string. */ | ||||
| 1811 | |||||
| 1812 | i = malloc0(offsetof(DnsTxtItem, data) + 1)(calloc(1, (__builtin_offsetof(DnsTxtItem, data) + 1))); /* for safety reasons we add an extra NUL byte */ | ||||
| 1813 | if (!i) | ||||
| 1814 | return -ENOMEM12; | ||||
| 1815 | |||||
| 1816 | *ret = i; | ||||
| 1817 | |||||
| 1818 | return 0; | ||||
| 1819 | } | ||||
| 1820 | |||||
| 1821 | static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { | ||||
| 1822 | /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ | ||||
| 1823 | [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", | ||||
| 1824 | [DNSSEC_ALGORITHM_DH] = "DH", | ||||
| 1825 | [DNSSEC_ALGORITHM_DSA] = "DSA", | ||||
| 1826 | [DNSSEC_ALGORITHM_ECC] = "ECC", | ||||
| 1827 | [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1", | ||||
| 1828 | [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1", | ||||
| 1829 | [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", | ||||
| 1830 | [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256", | ||||
| 1831 | [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512", | ||||
| 1832 | [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST", | ||||
| 1833 | [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256", | ||||
| 1834 | [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384", | ||||
| 1835 | [DNSSEC_ALGORITHM_ED25519] = "ED25519", | ||||
| 1836 | [DNSSEC_ALGORITHM_ED448] = "ED448", | ||||
| 1837 | [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", | ||||
| 1838 | [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", | ||||
| 1839 | [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", | ||||
| 1840 | }; | ||||
| 1841 | DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255)int dnssec_algorithm_to_string_alloc(int i, char **str) { char *s; if (i < 0 || i > 255) return -34; if (i < (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(dnssec_algorithm_table), typeof(&*(dnssec_algorithm_table ))), sizeof(dnssec_algorithm_table)/sizeof((dnssec_algorithm_table )[0]), ((void)0)))) { s = strdup(dnssec_algorithm_table[i]); if (!s) return -12; } else { if (asprintf(&s, "%i", i) < 0) return -12; } *str = s; return 0; } int dnssec_algorithm_from_string (const char *s) { int i; unsigned u = 0; if (!s) return (int) -1; for (i = 0; i < (int) __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(dnssec_algorithm_table ), typeof(&*(dnssec_algorithm_table))), sizeof(dnssec_algorithm_table )/sizeof((dnssec_algorithm_table)[0]), ((void)0))); i++) if ( streq_ptr(dnssec_algorithm_table[i], s)) return i; if (safe_atou (s, &u) >= 0 && u <= 255) return (int) u; return (int) -1; }; | ||||
| 1842 | |||||
| 1843 | static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = { | ||||
| 1844 | /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ | ||||
| 1845 | [DNSSEC_DIGEST_SHA1] = "SHA-1", | ||||
| 1846 | [DNSSEC_DIGEST_SHA256] = "SHA-256", | ||||
| 1847 | [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94", | ||||
| 1848 | [DNSSEC_DIGEST_SHA384] = "SHA-384", | ||||
| 1849 | }; | ||||
| 1850 | DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255)int dnssec_digest_to_string_alloc(int i, char **str) { char * s; if (i < 0 || i > 255) return -34; if (i < (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (dnssec_digest_table), typeof(&*(dnssec_digest_table))), sizeof (dnssec_digest_table)/sizeof((dnssec_digest_table)[0]), ((void )0)))) { s = strdup(dnssec_digest_table[i]); if (!s) return - 12; } else { if (asprintf(&s, "%i", i) < 0) return -12 ; } *str = s; return 0; } int dnssec_digest_from_string(const char *s) { int i; unsigned u = 0; if (!s) return (int) -1; for (i = 0; i < (int) __extension__ (__builtin_choose_expr( ! __builtin_types_compatible_p(typeof(dnssec_digest_table), typeof (&*(dnssec_digest_table))), sizeof(dnssec_digest_table)/sizeof ((dnssec_digest_table)[0]), ((void)0))); i++) if (streq_ptr(dnssec_digest_table [i], s)) return i; if (safe_atou(s, &u) >= 0 && u <= 255) return (int) u; return (int) -1; }; |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | #include <alloca.h> |
| 5 | #include <stddef.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include "macro.h" |
| 10 | |
| 11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
| 12 | |
| 13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
| 14 | |
| 15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
| 16 | ({ \ |
| 17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
| 18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
| 19 | }) |
| 20 | |
| 21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
| 22 | ({ \ |
| 23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
| 24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
| 25 | }) |
| 26 | |
| 27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
| 28 | |
| 29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
| 30 | |
| 31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
| 32 | |
| 33 | static inline void *mfree(void *memory) { |
| 34 | free(memory); |
| 35 | return NULL((void*)0); |
| 36 | } |
| 37 | |
| 38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
| 39 | ({ \ |
| 40 | free(a); \ |
| 41 | (a) = (b); \ |
| 42 | (b) = NULL((void*)0); \ |
| 43 | 0; \ |
| 44 | }) |
| 45 | |
| 46 | void* memdup(const void *p, size_t l) _alloc_(2); |
| 47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
| 48 | |
| 49 | static inline void freep(void *p) { |
| 50 | free(*(void**) p); |
| 51 | } |
| 52 | |
| 53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
| 54 | |
| 55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
| 56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
| 57 | } |
| 58 | |
| 59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
| 60 | if (size_multiply_overflow(size, need)) |
| 61 | return NULL((void*)0); |
| 62 | |
| 63 | return malloc(size * need); |
| 64 | } |
| 65 | |
| 66 | #if !HAVE_REALLOCARRAY1 |
| 67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
| 68 | if (size_multiply_overflow(size, need)) |
| 69 | return NULL((void*)0); |
| 70 | |
| 71 | return realloc(p, size * need); |
| 72 | } |
| 73 | #endif |
| 74 | |
| 75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
| 76 | if (size_multiply_overflow(size, need)) |
| 77 | return NULL((void*)0); |
| 78 | |
| 79 | return memdup(p, size * need); |
| 80 | } |
| 81 | |
| 82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
| 83 | if (size_multiply_overflow(size, need)) |
| 84 | return NULL((void*)0); |
| 85 | |
| 86 | return memdup_suffix0(p, size * need); |
| 87 | } |
| 88 | |
| 89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
| 90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
| 91 | |
| 92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 94 | |
| 95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 97 | |
| 98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
| 99 | ({ \ |
| 100 | char *_new_; \ |
| 101 | size_t _len_ = n; \ |
| 102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
| 103 | (void *) memset(_new_, 0, _len_); \ |
| 104 | }) |
| 105 | |
| 106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
| 107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
| 108 | ({ \ |
| 109 | void *_ptr_; \ |
| 110 | size_t _mask_ = (align) - 1; \ |
| 111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
| 112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
| 113 | }) |
| 114 | |
| 115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
| 116 | ({ \ |
| 117 | void *_new_; \ |
| 118 | size_t _size_ = (size); \ |
| 119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
| 120 | (void*)memset(_new_, 0, _size_); \ |
| 121 | }) |
| 122 | |
| 123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
| 124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
| 125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
| 126 | ({ \ |
| 127 | typeof(ptr) _ptr_ = (ptr); \ |
| 128 | (ptr) = NULL((void*)0); \ |
| 129 | _ptr_; \ |
| 130 | }) |