| File: | build-scan/../src/resolve/resolved-dns-question.c |
| Warning: | line 433, column 25 Potential leak of memory pointed to by 'q' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | ||||
| 3 | #include "alloc-util.h" | |||
| 4 | #include "dns-domain.h" | |||
| 5 | #include "dns-type.h" | |||
| 6 | #include "resolved-dns-question.h" | |||
| 7 | ||||
| 8 | DnsQuestion *dns_question_new(size_t n) { | |||
| 9 | DnsQuestion *q; | |||
| 10 | ||||
| 11 | assert(n > 0)do { if ((__builtin_expect(!!(!(n > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n > 0"), "../src/resolve/resolved-dns-question.c" , 11, __PRETTY_FUNCTION__); } while (0); | |||
| 12 | ||||
| 13 | q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n)(calloc(1, (__builtin_offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey *) * n))); | |||
| 14 | if (!q) | |||
| 15 | return NULL((void*)0); | |||
| 16 | ||||
| 17 | q->n_ref = 1; | |||
| 18 | q->n_allocated = n; | |||
| 19 | ||||
| 20 | return q; | |||
| 21 | } | |||
| 22 | ||||
| 23 | DnsQuestion *dns_question_ref(DnsQuestion *q) { | |||
| 24 | if (!q) | |||
| 25 | return NULL((void*)0); | |||
| 26 | ||||
| 27 | assert(q->n_ref > 0)do { if ((__builtin_expect(!!(!(q->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("q->n_ref > 0"), "../src/resolve/resolved-dns-question.c" , 27, __PRETTY_FUNCTION__); } while (0); | |||
| 28 | q->n_ref++; | |||
| 29 | return q; | |||
| 30 | } | |||
| 31 | ||||
| 32 | DnsQuestion *dns_question_unref(DnsQuestion *q) { | |||
| 33 | if (!q) | |||
| 34 | return NULL((void*)0); | |||
| 35 | ||||
| 36 | assert(q->n_ref > 0)do { if ((__builtin_expect(!!(!(q->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("q->n_ref > 0"), "../src/resolve/resolved-dns-question.c" , 36, __PRETTY_FUNCTION__); } while (0); | |||
| 37 | ||||
| 38 | if (q->n_ref == 1) { | |||
| 39 | size_t i; | |||
| 40 | ||||
| 41 | for (i = 0; i < q->n_keys; i++) | |||
| 42 | dns_resource_key_unref(q->keys[i]); | |||
| 43 | free(q); | |||
| 44 | } else | |||
| 45 | q->n_ref--; | |||
| 46 | ||||
| 47 | return NULL((void*)0); | |||
| 48 | } | |||
| 49 | ||||
| 50 | int dns_question_add(DnsQuestion *q, DnsResourceKey *key) { | |||
| 51 | size_t i; | |||
| 52 | int r; | |||
| 53 | ||||
| 54 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-dns-question.c" , 54, __PRETTY_FUNCTION__); } while (0); | |||
| 55 | ||||
| 56 | if (!q) | |||
| 57 | return -ENOSPC28; | |||
| 58 | ||||
| 59 | for (i = 0; i < q->n_keys; i++) { | |||
| 60 | r = dns_resource_key_equal(q->keys[i], key); | |||
| 61 | if (r < 0) | |||
| 62 | return r; | |||
| 63 | if (r > 0) | |||
| 64 | return 0; | |||
| 65 | } | |||
| 66 | ||||
| 67 | if (q->n_keys >= q->n_allocated) | |||
| 68 | return -ENOSPC28; | |||
| 69 | ||||
| 70 | q->keys[q->n_keys++] = dns_resource_key_ref(key); | |||
| 71 | return 0; | |||
| 72 | } | |||
| 73 | ||||
| 74 | int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) { | |||
| 75 | size_t i; | |||
| 76 | int r; | |||
| 77 | ||||
| 78 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-question.c" , 78, __PRETTY_FUNCTION__); } while (0); | |||
| 79 | ||||
| 80 | if (!q) | |||
| 81 | return 0; | |||
| 82 | ||||
| 83 | for (i = 0; i < q->n_keys; i++) { | |||
| 84 | r = dns_resource_key_match_rr(q->keys[i], rr, search_domain); | |||
| 85 | if (r != 0) | |||
| 86 | return r; | |||
| 87 | } | |||
| 88 | ||||
| 89 | return 0; | |||
| 90 | } | |||
| 91 | ||||
| 92 | int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) { | |||
| 93 | size_t i; | |||
| 94 | int r; | |||
| 95 | ||||
| 96 | assert(rr)do { if ((__builtin_expect(!!(!(rr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rr"), "../src/resolve/resolved-dns-question.c" , 96, __PRETTY_FUNCTION__); } while (0); | |||
| 97 | ||||
| 98 | if (!q) | |||
| 99 | return 0; | |||
| 100 | ||||
| 101 | if (!IN_SET(rr->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)({ _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(rr->key->type) { case DNS_TYPE_CNAME: case DNS_TYPE_DNAME: _found = 1; break; default: break; } _found; })) | |||
| 102 | return 0; | |||
| 103 | ||||
| 104 | for (i = 0; i < q->n_keys; i++) { | |||
| 105 | /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */ | |||
| 106 | if (!dns_type_may_redirect(q->keys[i]->type)) | |||
| 107 | return 0; | |||
| 108 | ||||
| 109 | r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain); | |||
| 110 | if (r != 0) | |||
| 111 | return r; | |||
| 112 | } | |||
| 113 | ||||
| 114 | return 0; | |||
| 115 | } | |||
| 116 | ||||
| 117 | int dns_question_is_valid_for_query(DnsQuestion *q) { | |||
| 118 | const char *name; | |||
| 119 | size_t i; | |||
| 120 | int r; | |||
| 121 | ||||
| 122 | if (!q) | |||
| 123 | return 0; | |||
| 124 | ||||
| 125 | if (q->n_keys <= 0) | |||
| 126 | return 0; | |||
| 127 | ||||
| 128 | if (q->n_keys > 65535) | |||
| 129 | return 0; | |||
| 130 | ||||
| 131 | name = dns_resource_key_name(q->keys[0]); | |||
| 132 | if (!name) | |||
| 133 | return 0; | |||
| 134 | ||||
| 135 | /* Check that all keys in this question bear the same name */ | |||
| 136 | for (i = 0; i < q->n_keys; i++) { | |||
| 137 | assert(q->keys[i])do { if ((__builtin_expect(!!(!(q->keys[i])),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("q->keys[i]"), "../src/resolve/resolved-dns-question.c" , 137, __PRETTY_FUNCTION__); } while (0); | |||
| 138 | ||||
| 139 | if (i > 0) { | |||
| 140 | r = dns_name_equal(dns_resource_key_name(q->keys[i]), name); | |||
| 141 | if (r <= 0) | |||
| 142 | return r; | |||
| 143 | } | |||
| 144 | ||||
| 145 | if (!dns_type_is_valid_query(q->keys[i]->type)) | |||
| 146 | return 0; | |||
| 147 | } | |||
| 148 | ||||
| 149 | return 1; | |||
| 150 | } | |||
| 151 | ||||
| 152 | int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) { | |||
| 153 | size_t j; | |||
| 154 | int r; | |||
| 155 | ||||
| 156 | assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("k"), "../src/resolve/resolved-dns-question.c" , 156, __PRETTY_FUNCTION__); } while (0); | |||
| 157 | ||||
| 158 | if (!a) | |||
| 159 | return 0; | |||
| 160 | ||||
| 161 | for (j = 0; j < a->n_keys; j++) { | |||
| 162 | r = dns_resource_key_equal(a->keys[j], k); | |||
| 163 | if (r != 0) | |||
| 164 | return r; | |||
| 165 | } | |||
| 166 | ||||
| 167 | return 0; | |||
| 168 | } | |||
| 169 | ||||
| 170 | int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) { | |||
| 171 | size_t j; | |||
| 172 | int r; | |||
| 173 | ||||
| 174 | if (a == b) | |||
| 175 | return 1; | |||
| 176 | ||||
| 177 | if (!a) | |||
| 178 | return !b || b->n_keys == 0; | |||
| 179 | if (!b) | |||
| 180 | return a->n_keys == 0; | |||
| 181 | ||||
| 182 | /* Checks if all keys in a are also contained b, and vice versa */ | |||
| 183 | ||||
| 184 | for (j = 0; j < a->n_keys; j++) { | |||
| 185 | r = dns_question_contains(b, a->keys[j]); | |||
| 186 | if (r <= 0) | |||
| 187 | return r; | |||
| 188 | } | |||
| 189 | ||||
| 190 | for (j = 0; j < b->n_keys; j++) { | |||
| 191 | r = dns_question_contains(a, b->keys[j]); | |||
| 192 | if (r <= 0) | |||
| 193 | return r; | |||
| 194 | } | |||
| 195 | ||||
| 196 | return 1; | |||
| 197 | } | |||
| 198 | ||||
| 199 | int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) { | |||
| 200 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *n = NULL((void*)0); | |||
| 201 | DnsResourceKey *key; | |||
| 202 | bool_Bool same = true1; | |||
| 203 | int r; | |||
| 204 | ||||
| 205 | assert(cname)do { if ((__builtin_expect(!!(!(cname)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cname"), "../src/resolve/resolved-dns-question.c" , 205, __PRETTY_FUNCTION__); } while (0); | |||
| 206 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c" , 206, __PRETTY_FUNCTION__); } while (0); | |||
| 207 | 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-question.c", 207, __PRETTY_FUNCTION__ ); } while (0); | |||
| 208 | ||||
| 209 | if (dns_question_size(q) <= 0) { | |||
| 210 | *ret = NULL((void*)0); | |||
| 211 | return 0; | |||
| 212 | } | |||
| 213 | ||||
| 214 | DNS_QUESTION_FOREACH(key, q)for (size_t __unique_prefix_i11 = ({ (key) = ((q) && ( q)->n_keys > 0) ? (q)->keys[0] : ((void*)0); 0; }); ( q) && (__unique_prefix_i11 < (q)->n_keys); __unique_prefix_i11 ++, (key) = (__unique_prefix_i11 < (q)->n_keys ? (q)-> keys[__unique_prefix_i11] : ((void*)0))) { | |||
| 215 | _cleanup_free___attribute__((cleanup(freep))) char *destination = NULL((void*)0); | |||
| 216 | const char *d; | |||
| 217 | ||||
| 218 | if (cname->key->type == DNS_TYPE_CNAME) | |||
| 219 | d = cname->cname.name; | |||
| 220 | else { | |||
| 221 | r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination); | |||
| 222 | if (r < 0) | |||
| 223 | return r; | |||
| 224 | if (r == 0) | |||
| 225 | continue; | |||
| 226 | ||||
| 227 | d = destination; | |||
| 228 | } | |||
| 229 | ||||
| 230 | r = dns_name_equal(dns_resource_key_name(key), d); | |||
| 231 | if (r < 0) | |||
| 232 | return r; | |||
| 233 | ||||
| 234 | if (r == 0) { | |||
| 235 | same = false0; | |||
| 236 | break; | |||
| 237 | } | |||
| 238 | } | |||
| 239 | ||||
| 240 | /* Fully the same, indicate we didn't do a thing */ | |||
| 241 | if (same) { | |||
| 242 | *ret = NULL((void*)0); | |||
| 243 | return 0; | |||
| 244 | } | |||
| 245 | ||||
| 246 | n = dns_question_new(q->n_keys); | |||
| 247 | if (!n) | |||
| 248 | return -ENOMEM12; | |||
| 249 | ||||
| 250 | /* Create a new question, and patch in the new name */ | |||
| 251 | DNS_QUESTION_FOREACH(key, q)for (size_t __unique_prefix_i12 = ({ (key) = ((q) && ( q)->n_keys > 0) ? (q)->keys[0] : ((void*)0); 0; }); ( q) && (__unique_prefix_i12 < (q)->n_keys); __unique_prefix_i12 ++, (key) = (__unique_prefix_i12 < (q)->n_keys ? (q)-> keys[__unique_prefix_i12] : ((void*)0))) { | |||
| 252 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *k = NULL((void*)0); | |||
| 253 | ||||
| 254 | k = dns_resource_key_new_redirect(key, cname); | |||
| 255 | if (!k) | |||
| 256 | return -ENOMEM12; | |||
| 257 | ||||
| 258 | r = dns_question_add(n, k); | |||
| 259 | if (r < 0) | |||
| 260 | return r; | |||
| 261 | } | |||
| 262 | ||||
| 263 | *ret = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; }); | |||
| 264 | ||||
| 265 | return 1; | |||
| 266 | } | |||
| 267 | ||||
| 268 | const char *dns_question_first_name(DnsQuestion *q) { | |||
| 269 | ||||
| 270 | if (!q) | |||
| 271 | return NULL((void*)0); | |||
| 272 | ||||
| 273 | if (q->n_keys < 1) | |||
| 274 | return NULL((void*)0); | |||
| 275 | ||||
| 276 | return dns_resource_key_name(q->keys[0]); | |||
| 277 | } | |||
| 278 | ||||
| 279 | int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool_Bool convert_idna) { | |||
| 280 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0); | |||
| 281 | _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0); | |||
| 282 | int r; | |||
| 283 | ||||
| 284 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c" , 284, __PRETTY_FUNCTION__); } while (0); | |||
| 285 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/resolve/resolved-dns-question.c" , 285, __PRETTY_FUNCTION__); } while (0); | |||
| 286 | ||||
| 287 | if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){2, 10, 0})/sizeof(int)]; switch(family) { case 2: case 10: case 0: _found = 1; break; default: break; } _found; })) | |||
| 288 | return -EAFNOSUPPORT97; | |||
| 289 | ||||
| 290 | if (convert_idna) { | |||
| 291 | r = dns_name_apply_idna(name, &buf); | |||
| 292 | if (r < 0) | |||
| 293 | return r; | |||
| 294 | if (r > 0 && !streq(name, buf)(strcmp((name),(buf)) == 0)) | |||
| 295 | name = buf; | |||
| 296 | else | |||
| 297 | /* We did not manage to create convert the idna name, or it's | |||
| 298 | * the same as the original name. We assume the caller already | |||
| 299 | * created an uncoverted question, so let's not repeat work | |||
| 300 | * unnecessarily. */ | |||
| 301 | return -EALREADY114; | |||
| 302 | } | |||
| 303 | ||||
| 304 | q = dns_question_new(family == AF_UNSPEC0 ? 2 : 1); | |||
| 305 | if (!q) | |||
| 306 | return -ENOMEM12; | |||
| 307 | ||||
| 308 | if (family != AF_INET610) { | |||
| 309 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
| 310 | ||||
| 311 | key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name); | |||
| 312 | if (!key) | |||
| 313 | return -ENOMEM12; | |||
| 314 | ||||
| 315 | r = dns_question_add(q, key); | |||
| 316 | if (r < 0) | |||
| 317 | return r; | |||
| 318 | } | |||
| 319 | ||||
| 320 | if (family != AF_INET2) { | |||
| 321 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
| 322 | ||||
| 323 | key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name); | |||
| 324 | if (!key) | |||
| 325 | return -ENOMEM12; | |||
| 326 | ||||
| 327 | r = dns_question_add(q, key); | |||
| 328 | if (r < 0) | |||
| 329 | return r; | |||
| 330 | } | |||
| 331 | ||||
| 332 | *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; }); | |||
| 333 | ||||
| 334 | return 0; | |||
| 335 | } | |||
| 336 | ||||
| 337 | int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) { | |||
| 338 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
| 339 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0); | |||
| 340 | _cleanup_free___attribute__((cleanup(freep))) char *reverse = NULL((void*)0); | |||
| 341 | int r; | |||
| 342 | ||||
| 343 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c" , 343, __PRETTY_FUNCTION__); } while (0); | |||
| 344 | assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("a"), "../src/resolve/resolved-dns-question.c" , 344, __PRETTY_FUNCTION__); } while (0); | |||
| 345 | ||||
| 346 | if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){2, 10, 0})/sizeof(int)]; switch(family) { case 2: case 10: case 0: _found = 1; break; default: break; } _found; })) | |||
| 347 | return -EAFNOSUPPORT97; | |||
| 348 | ||||
| 349 | r = dns_name_reverse(family, a, &reverse); | |||
| 350 | if (r < 0) | |||
| 351 | return r; | |||
| 352 | ||||
| 353 | q = dns_question_new(1); | |||
| 354 | if (!q) | |||
| 355 | return -ENOMEM12; | |||
| 356 | ||||
| 357 | key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); | |||
| 358 | if (!key) | |||
| 359 | return -ENOMEM12; | |||
| 360 | ||||
| 361 | reverse = NULL((void*)0); | |||
| 362 | ||||
| 363 | r = dns_question_add(q, key); | |||
| 364 | if (r < 0) | |||
| 365 | return r; | |||
| 366 | ||||
| 367 | *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; }); | |||
| 368 | ||||
| 369 | return 0; | |||
| 370 | } | |||
| 371 | ||||
| 372 | int dns_question_new_service( | |||
| 373 | DnsQuestion **ret, | |||
| 374 | const char *service, | |||
| 375 | const char *type, | |||
| 376 | const char *domain, | |||
| 377 | bool_Bool with_txt, | |||
| 378 | bool_Bool convert_idna) { | |||
| 379 | ||||
| 380 | _cleanup_(dns_resource_key_unrefp)__attribute__((cleanup(dns_resource_key_unrefp))) DnsResourceKey *key = NULL((void*)0); | |||
| 381 | _cleanup_(dns_question_unrefp)__attribute__((cleanup(dns_question_unrefp))) DnsQuestion *q = NULL((void*)0); | |||
| 382 | _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0), *joined = NULL((void*)0); | |||
| 383 | const char *name; | |||
| 384 | int r; | |||
| 385 | ||||
| 386 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/resolve/resolved-dns-question.c" , 386, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
| 387 | ||||
| 388 | /* We support three modes of invocation: | |||
| 389 | * | |||
| 390 | * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service | |||
| 391 | * type and possibly a service name. If specified in this way we assume it's already IDNA converted if | |||
| 392 | * that's necessary. | |||
| 393 | * | |||
| 394 | * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD | |||
| 395 | * style prefix. In this case we'll IDNA convert the domain, if that's requested. | |||
| 396 | * | |||
| 397 | * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put | |||
| 398 | * together. The service name is never IDNA converted, and the domain is if requested. | |||
| 399 | * | |||
| 400 | * It's not supported to specify a service name without a type, or no domain name. | |||
| 401 | */ | |||
| 402 | ||||
| 403 | if (!domain) | |||
| 404 | return -EINVAL22; | |||
| 405 | ||||
| 406 | if (type) { | |||
| 407 | if (convert_idna) { | |||
| 408 | r = dns_name_apply_idna(domain, &buf); | |||
| 409 | if (r < 0) | |||
| 410 | return r; | |||
| 411 | if (r > 0) | |||
| 412 | domain = buf; | |||
| 413 | } | |||
| 414 | ||||
| 415 | r = dns_service_join(service, type, domain, &joined); | |||
| 416 | if (r < 0) | |||
| 417 | return r; | |||
| 418 | ||||
| 419 | name = joined; | |||
| 420 | } else { | |||
| 421 | if (service) | |||
| 422 | return -EINVAL22; | |||
| 423 | ||||
| 424 | name = domain; | |||
| 425 | } | |||
| 426 | ||||
| 427 | q = dns_question_new(1 + with_txt); | |||
| 428 | if (!q
| |||
| 429 | return -ENOMEM12; | |||
| 430 | ||||
| 431 | key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name); | |||
| 432 | if (!key) | |||
| 433 | return -ENOMEM12; | |||
| ||||
| 434 | ||||
| 435 | r = dns_question_add(q, key); | |||
| 436 | if (r < 0) | |||
| 437 | return r; | |||
| 438 | ||||
| 439 | if (with_txt) { | |||
| 440 | dns_resource_key_unref(key); | |||
| 441 | key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name); | |||
| 442 | if (!key) | |||
| 443 | return -ENOMEM12; | |||
| 444 | ||||
| 445 | r = dns_question_add(q, key); | |||
| 446 | if (r < 0) | |||
| 447 | return r; | |||
| 448 | } | |||
| 449 | ||||
| 450 | *ret = TAKE_PTR(q)({ typeof(q) _ptr_ = (q); (q) = ((void*)0); _ptr_; }); | |||
| 451 | ||||
| 452 | return 0; | |||
| 453 | } |