| File: | build-scan/../src/resolve/resolved-mdns.c |
| Warning: | line 183, column 24 Potential leak of memory pointed to by 'remote' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
| 2 | |||||
| 3 | #include <resolv.h> | ||||
| 4 | #include <netinet/in.h> | ||||
| 5 | #include <arpa/inet.h> | ||||
| 6 | |||||
| 7 | #include "alloc-util.h" | ||||
| 8 | #include "fd-util.h" | ||||
| 9 | #include "resolved-manager.h" | ||||
| 10 | #include "resolved-mdns.h" | ||||
| 11 | |||||
| 12 | #define CLEAR_CACHE_FLUSH(x)(~(1 << 15) & (x)) (~MDNS_RR_CACHE_FLUSH(1 << 15) & (x)) | ||||
| 13 | |||||
| 14 | void manager_mdns_stop(Manager *m) { | ||||
| 15 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-mdns.c", 15 , __PRETTY_FUNCTION__); } while (0); | ||||
| 16 | |||||
| 17 | m->mdns_ipv4_event_source = sd_event_source_unref(m->mdns_ipv4_event_source); | ||||
| 18 | m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); | ||||
| 19 | |||||
| 20 | m->mdns_ipv6_event_source = sd_event_source_unref(m->mdns_ipv6_event_source); | ||||
| 21 | m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); | ||||
| 22 | } | ||||
| 23 | |||||
| 24 | int manager_mdns_start(Manager *m) { | ||||
| 25 | int r; | ||||
| 26 | |||||
| 27 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-mdns.c", 27 , __PRETTY_FUNCTION__); } while (0); | ||||
| 28 | |||||
| 29 | if (m->mdns_support == RESOLVE_SUPPORT_NO) | ||||
| 30 | return 0; | ||||
| 31 | |||||
| 32 | r = manager_mdns_ipv4_fd(m); | ||||
| 33 | if (r == -EADDRINUSE98) | ||||
| 34 | goto eaddrinuse; | ||||
| 35 | if (r < 0) | ||||
| 36 | return r; | ||||
| 37 | |||||
| 38 | if (socket_ipv6_is_supported()) { | ||||
| 39 | r = manager_mdns_ipv6_fd(m); | ||||
| 40 | if (r == -EADDRINUSE98) | ||||
| 41 | goto eaddrinuse; | ||||
| 42 | if (r < 0) | ||||
| 43 | return r; | ||||
| 44 | } | ||||
| 45 | |||||
| 46 | return 0; | ||||
| 47 | |||||
| 48 | eaddrinuse: | ||||
| 49 | log_warning("Another mDNS responder prohibits binding the socket to the same port. Turning off mDNS support.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 49, __func__, "Another mDNS responder prohibits binding the socket to the same port. Turning off mDNS support." ) : -abs(_e); }); | ||||
| 50 | m->mdns_support = RESOLVE_SUPPORT_NO; | ||||
| 51 | manager_mdns_stop(m); | ||||
| 52 | |||||
| 53 | return 0; | ||||
| 54 | } | ||||
| 55 | |||||
| 56 | static int mdns_rr_compare(const void *a, const void *b) { | ||||
| 57 | DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b; | ||||
| 58 | size_t m; | ||||
| 59 | int r; | ||||
| 60 | |||||
| 61 | assert(x)do { if ((__builtin_expect(!!(!(x)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("x"), "../src/resolve/resolved-mdns.c", 61 , __PRETTY_FUNCTION__); } while (0); | ||||
| 62 | assert(*x)do { if ((__builtin_expect(!!(!(*x)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("*x"), "../src/resolve/resolved-mdns.c", 62, __PRETTY_FUNCTION__); } while (0); | ||||
| 63 | assert(y)do { if ((__builtin_expect(!!(!(y)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("y"), "../src/resolve/resolved-mdns.c", 63 , __PRETTY_FUNCTION__); } while (0); | ||||
| 64 | assert(*y)do { if ((__builtin_expect(!!(!(*y)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("*y"), "../src/resolve/resolved-mdns.c", 64, __PRETTY_FUNCTION__); } while (0); | ||||
| 65 | |||||
| 66 | if (CLEAR_CACHE_FLUSH((*x)->key->class)(~(1 << 15) & ((*x)->key->class)) < CLEAR_CACHE_FLUSH((*y)->key->class)(~(1 << 15) & ((*y)->key->class))) | ||||
| 67 | return -1; | ||||
| 68 | else if (CLEAR_CACHE_FLUSH((*x)->key->class)(~(1 << 15) & ((*x)->key->class)) > CLEAR_CACHE_FLUSH((*y)->key->class)(~(1 << 15) & ((*y)->key->class))) | ||||
| 69 | return 1; | ||||
| 70 | |||||
| 71 | if ((*x)->key->type < (*y)->key->type) | ||||
| 72 | return -1; | ||||
| 73 | else if ((*x)->key->type > (*y)->key->type) | ||||
| 74 | return 1; | ||||
| 75 | |||||
| 76 | r = dns_resource_record_to_wire_format(*x, false0); | ||||
| 77 | if (r < 0) { | ||||
| 78 | log_warning_errno(r, "Can't wire-format RR: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 78, __func__, "Can't wire-format RR: %m" ) : -abs(_e); }); | ||||
| 79 | return 0; | ||||
| 80 | } | ||||
| 81 | |||||
| 82 | r = dns_resource_record_to_wire_format(*y, false0); | ||||
| 83 | if (r < 0) { | ||||
| 84 | log_warning_errno(r, "Can't wire-format RR: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 84, __func__, "Can't wire-format RR: %m" ) : -abs(_e); }); | ||||
| 85 | return 0; | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y))__extension__ ({ const typeof((DNS_RESOURCE_RECORD_RDATA_SIZE (*x))) __unique_prefix_A29 = ((DNS_RESOURCE_RECORD_RDATA_SIZE (*x))); const typeof((DNS_RESOURCE_RECORD_RDATA_SIZE(*y))) __unique_prefix_B30 = ((DNS_RESOURCE_RECORD_RDATA_SIZE(*y))); __unique_prefix_A29 < __unique_prefix_B30 ? __unique_prefix_A29 : __unique_prefix_B30 ; }); | ||||
| 89 | |||||
| 90 | r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m); | ||||
| 91 | if (r != 0) | ||||
| 92 | return r; | ||||
| 93 | |||||
| 94 | if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y)) | ||||
| 95 | return -1; | ||||
| 96 | else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y)) | ||||
| 97 | return 1; | ||||
| 98 | |||||
| 99 | return 0; | ||||
| 100 | } | ||||
| 101 | |||||
| 102 | static int proposed_rrs_cmp(DnsResourceRecord **x, unsigned x_size, DnsResourceRecord **y, unsigned y_size) { | ||||
| 103 | unsigned m; | ||||
| 104 | int r; | ||||
| 105 | |||||
| 106 | m = MIN(x_size, y_size)__extension__ ({ const typeof((x_size)) __unique_prefix_A31 = ((x_size)); const typeof((y_size)) __unique_prefix_B32 = ((y_size )); __unique_prefix_A31 < __unique_prefix_B32 ? __unique_prefix_A31 : __unique_prefix_B32; }); | ||||
| 107 | for (unsigned i = 0; i < m; i++) { | ||||
| 108 | r = mdns_rr_compare(&x[i], &y[i]); | ||||
| 109 | if (r != 0) | ||||
| 110 | return r; | ||||
| 111 | } | ||||
| 112 | |||||
| 113 | if (x_size < y_size) | ||||
| 114 | return -1; | ||||
| 115 | if (x_size > y_size) | ||||
| 116 | return 1; | ||||
| 117 | |||||
| 118 | return 0; | ||||
| 119 | } | ||||
| 120 | |||||
| 121 | static int mdns_packet_extract_matching_rrs(DnsPacket *p, DnsResourceKey *key, DnsResourceRecord ***ret_rrs) { | ||||
| 122 | _cleanup_free___attribute__((cleanup(freep))) DnsResourceRecord **list = NULL((void*)0); | ||||
| 123 | unsigned n = 0, size = 0; | ||||
| 124 | int r; | ||||
| 125 | |||||
| 126 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-mdns.c", 126 , __PRETTY_FUNCTION__); } while (0); | ||||
| 127 | assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("key"), "../src/resolve/resolved-mdns.c" , 127, __PRETTY_FUNCTION__); } while (0); | ||||
| 128 | assert(ret_rrs)do { if ((__builtin_expect(!!(!(ret_rrs)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret_rrs"), "../src/resolve/resolved-mdns.c" , 128, __PRETTY_FUNCTION__); } while (0); | ||||
| 129 | assert_return(DNS_PACKET_NSCOUNT(p) > 0, -EINVAL)do { if (!(((__builtin_expect(!!(be16toh(((DnsPacketHeader*) DNS_PACKET_DATA (p))->nscount) > 0),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("DNS_PACKET_NSCOUNT(p) > 0"), "../src/resolve/resolved-mdns.c" , 129, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | ||||
| 130 | |||||
| 131 | for (size_t i = DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount); i < (DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount) + DNS_PACKET_NSCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->nscount)); i++) { | ||||
| 132 | r = dns_resource_key_match_rr(key, p->answer->items[i].rr, NULL((void*)0)); | ||||
| 133 | if (r < 0) | ||||
| 134 | return r; | ||||
| 135 | if (r > 0) | ||||
| 136 | size++; | ||||
| 137 | } | ||||
| 138 | |||||
| 139 | if (size
| ||||
| 140 | return 0; | ||||
| 141 | |||||
| 142 | list = new(DnsResourceRecord *, size)((DnsResourceRecord **) malloc_multiply(sizeof(DnsResourceRecord *), (size))); | ||||
| 143 | if (!list) | ||||
| 144 | return -ENOMEM12; | ||||
| 145 | |||||
| 146 | for (size_t i = DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount); i < (DNS_PACKET_ANCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->ancount) + DNS_PACKET_NSCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->nscount)); i++) { | ||||
| 147 | r = dns_resource_key_match_rr(key, p->answer->items[i].rr, NULL((void*)0)); | ||||
| 148 | if (r < 0) | ||||
| 149 | return r; | ||||
| 150 | if (r > 0) | ||||
| 151 | list[n++] = p->answer->items[i].rr; | ||||
| 152 | } | ||||
| 153 | assert(n == size)do { if ((__builtin_expect(!!(!(n == size)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n == size"), "../src/resolve/resolved-mdns.c" , 153, __PRETTY_FUNCTION__); } while (0); | ||||
| 154 | qsort_safe(list, size, sizeof(DnsResourceRecord*), mdns_rr_compare); | ||||
| 155 | |||||
| 156 | *ret_rrs = TAKE_PTR(list)({ typeof(list) _ptr_ = (list); (list) = ((void*)0); _ptr_; } ); | ||||
| 157 | |||||
| 158 | return size; | ||||
| 159 | } | ||||
| 160 | |||||
| 161 | static int mdns_do_tiebreak(DnsResourceKey *key, DnsAnswer *answer, DnsPacket *p) { | ||||
| 162 | _cleanup_free___attribute__((cleanup(freep))) DnsResourceRecord **our = NULL((void*)0), **remote = NULL((void*)0); | ||||
| 163 | DnsResourceRecord *rr; | ||||
| 164 | size_t i = 0, size; | ||||
| 165 | int r; | ||||
| 166 | |||||
| 167 | size = dns_answer_size(answer); | ||||
| 168 | our = new(DnsResourceRecord *, size)((DnsResourceRecord **) malloc_multiply(sizeof(DnsResourceRecord *), (size))); | ||||
| 169 | if (!our) | ||||
| 170 | return -ENOMEM12; | ||||
| 171 | |||||
| 172 | DNS_ANSWER_FOREACH(rr, answer)for (size_t __unique_prefix_i33 = ({ (rr) = ((answer) && (answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void *)0); 0; }); (answer) && (__unique_prefix_i33 < (answer )->n_rrs); __unique_prefix_i33++, (rr) = (__unique_prefix_i33 < (answer)->n_rrs ? (answer)->items[__unique_prefix_i33 ].rr : ((void*)0))) | ||||
| 173 | our[i++] = rr; | ||||
| 174 | qsort_safe(our, size, sizeof(DnsResourceRecord*), mdns_rr_compare); | ||||
| 175 | |||||
| 176 | r = mdns_packet_extract_matching_rrs(p, key, &remote); | ||||
| 177 | if (r
| ||||
| 178 | return r; | ||||
| 179 | |||||
| 180 | assert(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/resolve/resolved-mdns.c" , 180, __PRETTY_FUNCTION__); } while (0); | ||||
| 181 | |||||
| 182 | if (proposed_rrs_cmp(remote, r, our, size) > 0) | ||||
| 183 | return 1; | ||||
| |||||
| 184 | |||||
| 185 | return 0; | ||||
| 186 | } | ||||
| 187 | |||||
| 188 | static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) { | ||||
| 189 | _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *full_answer = NULL((void*)0); | ||||
| 190 | _cleanup_(dns_packet_unrefp)__attribute__((cleanup(dns_packet_unrefp))) DnsPacket *reply = NULL((void*)0); | ||||
| 191 | DnsResourceKey *key = NULL((void*)0); | ||||
| 192 | DnsResourceRecord *rr; | ||||
| 193 | bool_Bool tentative = false0; | ||||
| 194 | int r; | ||||
| 195 | |||||
| 196 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-mdns.c", 196 , __PRETTY_FUNCTION__); } while (0); | ||||
| 197 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-mdns.c", 197 , __PRETTY_FUNCTION__); } while (0); | ||||
| 198 | |||||
| 199 | r = dns_packet_extract(p); | ||||
| 200 | if (r < 0) | ||||
| 201 | return log_debug_errno(r, "Failed to extract resource records from incoming packet: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 201, __func__, "Failed to extract resource records from incoming packet: %m" ) : -abs(_e); }); | ||||
| 202 | |||||
| 203 | assert_return((dns_question_size(p->question) > 0), -EINVAL)do { if (!(((__builtin_expect(!!((dns_question_size(p->question ) > 0)),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("(dns_question_size(p->question) > 0)"), "../src/resolve/resolved-mdns.c" , 203, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | ||||
| 204 | |||||
| 205 | DNS_QUESTION_FOREACH(key, p->question)for (size_t __unique_prefix_i34 = ({ (key) = ((p->question ) && (p->question)->n_keys > 0) ? (p->question )->keys[0] : ((void*)0); 0; }); (p->question) && (__unique_prefix_i34 < (p->question)->n_keys); __unique_prefix_i34 ++, (key) = (__unique_prefix_i34 < (p->question)->n_keys ? (p->question)->keys[__unique_prefix_i34] : ((void*)0 ))) { | ||||
| 206 | _cleanup_(dns_answer_unrefp)__attribute__((cleanup(dns_answer_unrefp))) DnsAnswer *answer = NULL((void*)0), *soa = NULL((void*)0); | ||||
| 207 | |||||
| 208 | r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative); | ||||
| 209 | if (r < 0) | ||||
| 210 | return log_debug_errno(r, "Failed to lookup key: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 210, __func__, "Failed to lookup key: %m" ) : -abs(_e); }); | ||||
| 211 | |||||
| 212 | if (tentative && DNS_PACKET_NSCOUNT(p)be16toh(((DnsPacketHeader*) DNS_PACKET_DATA(p))->nscount) > 0) { | ||||
| 213 | /* | ||||
| 214 | * A race condition detected with the probe packet from | ||||
| 215 | * a remote host. | ||||
| 216 | * Do simultaneous probe tiebreaking as described in | ||||
| 217 | * RFC 6762, Section 8.2. In case we lost don't reply | ||||
| 218 | * the question and withdraw conflicting RRs. | ||||
| 219 | */ | ||||
| 220 | r = mdns_do_tiebreak(key, answer, p); | ||||
| 221 | if (r < 0) | ||||
| 222 | return log_debug_errno(r, "Failed to do tiebreaking")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 222, __func__, "Failed to do tiebreaking" ) : -abs(_e); }); | ||||
| 223 | |||||
| 224 | if (r > 0) { /* we lost */ | ||||
| 225 | DNS_ANSWER_FOREACH(rr, answer)for (size_t __unique_prefix_i35 = ({ (rr) = ((answer) && (answer)->n_rrs > 0) ? (answer)->items[0].rr : ((void *)0); 0; }); (answer) && (__unique_prefix_i35 < (answer )->n_rrs); __unique_prefix_i35++, (rr) = (__unique_prefix_i35 < (answer)->n_rrs ? (answer)->items[__unique_prefix_i35 ].rr : ((void*)0))) { | ||||
| 226 | DnsZoneItem *i; | ||||
| 227 | |||||
| 228 | i = dns_zone_get(&s->zone, rr); | ||||
| 229 | if (i) | ||||
| 230 | dns_zone_item_conflict(i); | ||||
| 231 | } | ||||
| 232 | |||||
| 233 | continue; | ||||
| 234 | } | ||||
| 235 | } | ||||
| 236 | |||||
| 237 | r = dns_answer_extend(&full_answer, answer); | ||||
| 238 | if (r < 0) | ||||
| 239 | return log_debug_errno(r, "Failed to extend answer: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 239, __func__, "Failed to extend answer: %m" ) : -abs(_e); }); | ||||
| 240 | } | ||||
| 241 | |||||
| 242 | if (dns_answer_isempty(full_answer)) | ||||
| 243 | return 0; | ||||
| 244 | |||||
| 245 | r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p)((DnsPacketHeader*) DNS_PACKET_DATA(p))->id, DNS_RCODE_SUCCESS, NULL((void*)0), full_answer, NULL((void*)0), false0, &reply); | ||||
| 246 | if (r < 0) | ||||
| 247 | return log_debug_errno(r, "Failed to build reply packet: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 247, __func__, "Failed to build reply packet: %m" ) : -abs(_e); }); | ||||
| 248 | |||||
| 249 | if (!ratelimit_below(&s->ratelimit)) | ||||
| 250 | return 0; | ||||
| 251 | |||||
| 252 | r = dns_scope_emit_udp(s, -1, reply); | ||||
| 253 | if (r < 0) | ||||
| 254 | return log_debug_errno(r, "Failed to send reply packet: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 254, __func__, "Failed to send reply packet: %m" ) : -abs(_e); }); | ||||
| 255 | |||||
| 256 | return 0; | ||||
| 257 | } | ||||
| 258 | |||||
| 259 | static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { | ||||
| 260 | _cleanup_(dns_packet_unrefp)__attribute__((cleanup(dns_packet_unrefp))) DnsPacket *p = NULL((void*)0); | ||||
| 261 | Manager *m = userdata; | ||||
| 262 | DnsScope *scope; | ||||
| 263 | int r; | ||||
| 264 | |||||
| 265 | r = manager_recv(m, fd, DNS_PROTOCOL_MDNS, &p); | ||||
| 266 | if (r <= 0) | ||||
| |||||
| 267 | return r; | ||||
| 268 | |||||
| 269 | if (manager_our_packet(m, p)) | ||||
| 270 | return 0; | ||||
| 271 | |||||
| 272 | scope = manager_find_scope(m, p); | ||||
| 273 | if (!scope) { | ||||
| 274 | log_debug("Got mDNS UDP packet on unknown scope. Ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 274, __func__, "Got mDNS UDP packet on unknown scope. Ignoring." ) : -abs(_e); }); | ||||
| 275 | return 0; | ||||
| 276 | } | ||||
| 277 | |||||
| 278 | if (dns_packet_validate_reply(p) > 0) { | ||||
| 279 | DnsResourceRecord *rr; | ||||
| 280 | |||||
| 281 | log_debug("Got mDNS reply packet")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 281, __func__, "Got mDNS reply packet" ) : -abs(_e); }); | ||||
| 282 | |||||
| 283 | /* | ||||
| 284 | * mDNS is different from regular DNS and LLMNR with regard to handling responses. | ||||
| 285 | * While on other protocols, we can ignore every answer that doesn't match a question | ||||
| 286 | * we broadcast earlier, RFC6762, section 18.1 recommends looking at and caching all | ||||
| 287 | * incoming information, regardless of the DNS packet ID. | ||||
| 288 | * | ||||
| 289 | * Hence, extract the packet here, and try to find a transaction for answer the we got | ||||
| 290 | * and complete it. Also store the new information in scope's cache. | ||||
| 291 | */ | ||||
| 292 | r = dns_packet_extract(p); | ||||
| 293 | if (r < 0) { | ||||
| 294 | log_debug("mDNS packet extraction failed.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 294, __func__, "mDNS packet extraction failed." ) : -abs(_e); }); | ||||
| 295 | return 0; | ||||
| 296 | } | ||||
| 297 | |||||
| 298 | dns_scope_check_conflicts(scope, p); | ||||
| 299 | |||||
| 300 | DNS_ANSWER_FOREACH(rr, p->answer)for (size_t __unique_prefix_i36 = ({ (rr) = ((p->answer) && (p->answer)->n_rrs > 0) ? (p->answer)->items[ 0].rr : ((void*)0); 0; }); (p->answer) && (__unique_prefix_i36 < (p->answer)->n_rrs); __unique_prefix_i36++, (rr) = (__unique_prefix_i36 < (p->answer)->n_rrs ? (p-> answer)->items[__unique_prefix_i36].rr : ((void*)0))) { | ||||
| 301 | const char *name = dns_resource_key_name(rr->key); | ||||
| 302 | DnsTransaction *t; | ||||
| 303 | |||||
| 304 | /* If the received reply packet contains ANY record that is not .local or .in-addr.arpa, | ||||
| 305 | * we assume someone's playing tricks on us and discard the packet completely. */ | ||||
| 306 | if (!(dns_name_endswith(name, "in-addr.arpa") > 0 || | ||||
| 307 | dns_name_endswith(name, "local") > 0)) | ||||
| 308 | return 0; | ||||
| 309 | |||||
| 310 | if (rr->ttl == 0) { | ||||
| 311 | log_debug("Got a goodbye packet")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 311, __func__, "Got a goodbye packet" ) : -abs(_e); }); | ||||
| 312 | /* See the section 10.1 of RFC6762 */ | ||||
| 313 | rr->ttl = 1; | ||||
| 314 | } | ||||
| 315 | |||||
| 316 | t = dns_scope_find_transaction(scope, rr->key, false0); | ||||
| 317 | if (t) | ||||
| 318 | dns_transaction_process_reply(t, p); | ||||
| 319 | |||||
| 320 | /* Also look for the various types of ANY transactions */ | ||||
| 321 | t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(rr->key))((DnsResourceKey) { .n_ref = (unsigned) -1, .class = rr->key ->class, .type = DNS_TYPE_ANY, ._name = (char*) dns_resource_key_name (rr->key), }), false0); | ||||
| 322 | if (t) | ||||
| 323 | dns_transaction_process_reply(t, p); | ||||
| 324 | |||||
| 325 | t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, rr->key->type, dns_resource_key_name(rr->key))((DnsResourceKey) { .n_ref = (unsigned) -1, .class = DNS_CLASS_ANY , .type = rr->key->type, ._name = (char*) dns_resource_key_name (rr->key), }), false0); | ||||
| 326 | if (t) | ||||
| 327 | dns_transaction_process_reply(t, p); | ||||
| 328 | |||||
| 329 | t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, DNS_TYPE_ANY, dns_resource_key_name(rr->key))((DnsResourceKey) { .n_ref = (unsigned) -1, .class = DNS_CLASS_ANY , .type = DNS_TYPE_ANY, ._name = (char*) dns_resource_key_name (rr->key), }), false0); | ||||
| 330 | if (t) | ||||
| 331 | dns_transaction_process_reply(t, p); | ||||
| 332 | } | ||||
| 333 | |||||
| 334 | dns_cache_put(&scope->cache, NULL((void*)0), DNS_PACKET_RCODE(p), p->answer, false0, (uint32_t) -1, 0, p->family, &p->sender); | ||||
| 335 | |||||
| 336 | } else if (dns_packet_validate_query(p) > 0) { | ||||
| 337 | log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 337, __func__, "Got mDNS query packet for id %u" , ((DnsPacketHeader*) DNS_PACKET_DATA(p))->id) : -abs(_e); }); | ||||
| 338 | |||||
| 339 | r = mdns_scope_process_query(scope, p); | ||||
| 340 | if (r < 0) { | ||||
| 341 | log_debug_errno(r, "mDNS query processing failed: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 341, __func__, "mDNS query processing failed: %m" ) : -abs(_e); }); | ||||
| 342 | return 0; | ||||
| 343 | } | ||||
| 344 | } else | ||||
| 345 | log_debug("Invalid mDNS UDP packet.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 345, __func__, "Invalid mDNS UDP packet." ) : -abs(_e); }); | ||||
| 346 | |||||
| 347 | return 0; | ||||
| 348 | } | ||||
| 349 | |||||
| 350 | int manager_mdns_ipv4_fd(Manager *m) { | ||||
| 351 | union sockaddr_union sa = { | ||||
| 352 | .in.sin_family = AF_INET2, | ||||
| 353 | .in.sin_port = htobe16(MDNS_PORT5353), | ||||
| 354 | }; | ||||
| 355 | static const int one = 1, pmtu = IP_PMTUDISC_DONT0, ttl = 255; | ||||
| 356 | int r; | ||||
| 357 | |||||
| 358 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-mdns.c", 358 , __PRETTY_FUNCTION__); } while (0); | ||||
| 359 | |||||
| 360 | if (m->mdns_ipv4_fd >= 0) | ||||
| 361 | return m->mdns_ipv4_fd; | ||||
| 362 | |||||
| 363 | m->mdns_ipv4_fd = socket(AF_INET2, SOCK_DGRAMSOCK_DGRAM|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, 0); | ||||
| 364 | if (m->mdns_ipv4_fd < 0) | ||||
| 365 | return log_error_errno(errno, "mDNS-IPv4: Failed to create socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 365, __func__ , "mDNS-IPv4: Failed to create socket: %m") : -abs(_e); }); | ||||
| 366 | |||||
| 367 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_TTL2, &ttl, sizeof(ttl)); | ||||
| 368 | if (r < 0) { | ||||
| 369 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_TTL: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 369, __func__ , "mDNS-IPv4: Failed to set IP_TTL: %m") : -abs(_e); }); | ||||
| 370 | goto fail; | ||||
| 371 | } | ||||
| 372 | |||||
| 373 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_MULTICAST_TTL33, &ttl, sizeof(ttl)); | ||||
| 374 | if (r < 0) { | ||||
| 375 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_MULTICAST_TTL: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 375, __func__ , "mDNS-IPv4: Failed to set IP_MULTICAST_TTL: %m") : -abs(_e) ; }); | ||||
| 376 | goto fail; | ||||
| 377 | } | ||||
| 378 | |||||
| 379 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_MULTICAST_LOOP34, &one, sizeof(one)); | ||||
| 380 | if (r < 0) { | ||||
| 381 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_MULTICAST_LOOP: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 381, __func__ , "mDNS-IPv4: Failed to set IP_MULTICAST_LOOP: %m") : -abs(_e ); }); | ||||
| 382 | goto fail; | ||||
| 383 | } | ||||
| 384 | |||||
| 385 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_PKTINFO8, &one, sizeof(one)); | ||||
| 386 | if (r < 0) { | ||||
| 387 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_PKTINFO: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 387, __func__ , "mDNS-IPv4: Failed to set IP_PKTINFO: %m") : -abs(_e); }); | ||||
| 388 | goto fail; | ||||
| 389 | } | ||||
| 390 | |||||
| 391 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_RECVTTL12, &one, sizeof(one)); | ||||
| 392 | if (r < 0) { | ||||
| 393 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_RECVTTL: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 393, __func__ , "mDNS-IPv4: Failed to set IP_RECVTTL: %m") : -abs(_e); }); | ||||
| 394 | goto fail; | ||||
| 395 | } | ||||
| 396 | |||||
| 397 | /* Disable Don't-Fragment bit in the IP header */ | ||||
| 398 | r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IPIPPROTO_IP, IP_MTU_DISCOVER10, &pmtu, sizeof(pmtu)); | ||||
| 399 | if (r < 0) { | ||||
| 400 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set IP_MTU_DISCOVER: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 400, __func__ , "mDNS-IPv4: Failed to set IP_MTU_DISCOVER: %m") : -abs(_e); }); | ||||
| 401 | goto fail; | ||||
| 402 | } | ||||
| 403 | |||||
| 404 | /* See the section 15.1 of RFC6762 */ | ||||
| 405 | /* first try to bind without SO_REUSEADDR to detect another mDNS responder */ | ||||
| 406 | r = bind(m->mdns_ipv4_fd, &sa.sa, sizeof(sa.in)); | ||||
| 407 | if (r < 0) { | ||||
| 408 | if (errno(*__errno_location ()) != EADDRINUSE98) { | ||||
| 409 | r = log_error_errno(errno, "mDNS-IPv4: Failed to bind socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 409, __func__ , "mDNS-IPv4: Failed to bind socket: %m") : -abs(_e); }); | ||||
| 410 | goto fail; | ||||
| 411 | } | ||||
| 412 | |||||
| 413 | log_warning("mDNS-IPv4: There appears to be another mDNS responder running, or previously systemd-resolved crashed with some outstanding transfers.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 413, __func__, "mDNS-IPv4: There appears to be another mDNS responder running, or previously systemd-resolved crashed with some outstanding transfers." ) : -abs(_e); }); | ||||
| 414 | |||||
| 415 | /* try again with SO_REUSEADDR */ | ||||
| 416 | r = setsockopt(m->mdns_ipv4_fd, SOL_SOCKET1, SO_REUSEADDR2, &one, sizeof(one)); | ||||
| 417 | if (r < 0) { | ||||
| 418 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set SO_REUSEADDR: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 418, __func__ , "mDNS-IPv4: Failed to set SO_REUSEADDR: %m") : -abs(_e); }); | ||||
| 419 | goto fail; | ||||
| 420 | } | ||||
| 421 | |||||
| 422 | r = bind(m->mdns_ipv4_fd, &sa.sa, sizeof(sa.in)); | ||||
| 423 | if (r < 0) { | ||||
| 424 | r = log_error_errno(errno, "mDNS-IPv4: Failed to bind socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 424, __func__ , "mDNS-IPv4: Failed to bind socket: %m") : -abs(_e); }); | ||||
| 425 | goto fail; | ||||
| 426 | } | ||||
| 427 | } else { | ||||
| 428 | /* enable SO_REUSEADDR for the case that the user really wants multiple mDNS responders */ | ||||
| 429 | r = setsockopt(m->mdns_ipv4_fd, SOL_SOCKET1, SO_REUSEADDR2, &one, sizeof(one)); | ||||
| 430 | if (r < 0) { | ||||
| 431 | r = log_error_errno(errno, "mDNS-IPv4: Failed to set SO_REUSEADDR: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 431, __func__ , "mDNS-IPv4: Failed to set SO_REUSEADDR: %m") : -abs(_e); }); | ||||
| 432 | goto fail; | ||||
| 433 | } | ||||
| 434 | } | ||||
| 435 | |||||
| 436 | r = sd_event_add_io(m->event, &m->mdns_ipv4_event_source, m->mdns_ipv4_fd, EPOLLINEPOLLIN, on_mdns_packet, m); | ||||
| 437 | if (r < 0) | ||||
| 438 | goto fail; | ||||
| 439 | |||||
| 440 | return m->mdns_ipv4_fd; | ||||
| 441 | |||||
| 442 | fail: | ||||
| 443 | m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); | ||||
| 444 | return r; | ||||
| 445 | } | ||||
| 446 | |||||
| 447 | int manager_mdns_ipv6_fd(Manager *m) { | ||||
| 448 | union sockaddr_union sa = { | ||||
| 449 | .in6.sin6_family = AF_INET610, | ||||
| 450 | .in6.sin6_port = htobe16(MDNS_PORT5353), | ||||
| 451 | }; | ||||
| 452 | static const int one = 1, ttl = 255; | ||||
| 453 | int r; | ||||
| 454 | |||||
| 455 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-mdns.c", 455 , __PRETTY_FUNCTION__); } while (0); | ||||
| 456 | |||||
| 457 | if (m->mdns_ipv6_fd >= 0) | ||||
| 458 | return m->mdns_ipv6_fd; | ||||
| 459 | |||||
| 460 | m->mdns_ipv6_fd = socket(AF_INET610, SOCK_DGRAMSOCK_DGRAM|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, 0); | ||||
| 461 | if (m->mdns_ipv6_fd < 0) | ||||
| 462 | return log_error_errno(errno, "mDNS-IPv6: Failed to create socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 462, __func__ , "mDNS-IPv6: Failed to create socket: %m") : -abs(_e); }); | ||||
| 463 | |||||
| 464 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_UNICAST_HOPS16, &ttl, sizeof(ttl)); | ||||
| 465 | if (r < 0) { | ||||
| 466 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_UNICAST_HOPS: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 466, __func__ , "mDNS-IPv6: Failed to set IPV6_UNICAST_HOPS: %m") : -abs(_e ); }); | ||||
| 467 | goto fail; | ||||
| 468 | } | ||||
| 469 | |||||
| 470 | /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ | ||||
| 471 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_MULTICAST_HOPS18, &ttl, sizeof(ttl)); | ||||
| 472 | if (r < 0) { | ||||
| 473 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_MULTICAST_HOPS: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 473, __func__ , "mDNS-IPv6: Failed to set IPV6_MULTICAST_HOPS: %m") : -abs( _e); }); | ||||
| 474 | goto fail; | ||||
| 475 | } | ||||
| 476 | |||||
| 477 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_MULTICAST_LOOP19, &one, sizeof(one)); | ||||
| 478 | if (r < 0) { | ||||
| 479 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_MULTICAST_LOOP: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 479, __func__ , "mDNS-IPv6: Failed to set IPV6_MULTICAST_LOOP: %m") : -abs( _e); }); | ||||
| 480 | goto fail; | ||||
| 481 | } | ||||
| 482 | |||||
| 483 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_V6ONLY26, &one, sizeof(one)); | ||||
| 484 | if (r < 0) { | ||||
| 485 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_V6ONLY: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 485, __func__ , "mDNS-IPv6: Failed to set IPV6_V6ONLY: %m") : -abs(_e); }); | ||||
| 486 | goto fail; | ||||
| 487 | } | ||||
| 488 | |||||
| 489 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_RECVPKTINFO49, &one, sizeof(one)); | ||||
| 490 | if (r < 0) { | ||||
| 491 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_RECVPKTINFO: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 491, __func__ , "mDNS-IPv6: Failed to set IPV6_RECVPKTINFO: %m") : -abs(_e) ; }); | ||||
| 492 | goto fail; | ||||
| 493 | } | ||||
| 494 | |||||
| 495 | r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_RECVHOPLIMIT51, &one, sizeof(one)); | ||||
| 496 | if (r < 0) { | ||||
| 497 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set IPV6_RECVHOPLIMIT: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 497, __func__ , "mDNS-IPv6: Failed to set IPV6_RECVHOPLIMIT: %m") : -abs(_e ); }); | ||||
| 498 | goto fail; | ||||
| 499 | } | ||||
| 500 | |||||
| 501 | /* See the section 15.1 of RFC6762 */ | ||||
| 502 | /* first try to bind without SO_REUSEADDR to detect another mDNS responder */ | ||||
| 503 | r = bind(m->mdns_ipv6_fd, &sa.sa, sizeof(sa.in6)); | ||||
| 504 | if (r < 0) { | ||||
| 505 | if (errno(*__errno_location ()) != EADDRINUSE98) { | ||||
| 506 | r = log_error_errno(errno, "mDNS-IPv6: Failed to bind socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 506, __func__ , "mDNS-IPv6: Failed to bind socket: %m") : -abs(_e); }); | ||||
| 507 | goto fail; | ||||
| 508 | } | ||||
| 509 | |||||
| 510 | log_warning("mDNS-IPv6: There appears to be another mDNS responder running, or previously systemd-resolved crashed with some outstanding transfers.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/resolve/resolved-mdns.c", 510, __func__, "mDNS-IPv6: There appears to be another mDNS responder running, or previously systemd-resolved crashed with some outstanding transfers." ) : -abs(_e); }); | ||||
| 511 | |||||
| 512 | /* try again with SO_REUSEADDR */ | ||||
| 513 | r = setsockopt(m->mdns_ipv6_fd, SOL_SOCKET1, SO_REUSEADDR2, &one, sizeof(one)); | ||||
| 514 | if (r < 0) { | ||||
| 515 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set SO_REUSEADDR: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 515, __func__ , "mDNS-IPv6: Failed to set SO_REUSEADDR: %m") : -abs(_e); }); | ||||
| 516 | goto fail; | ||||
| 517 | } | ||||
| 518 | |||||
| 519 | r = bind(m->mdns_ipv6_fd, &sa.sa, sizeof(sa.in6)); | ||||
| 520 | if (r < 0) { | ||||
| 521 | r = log_error_errno(errno, "mDNS-IPv6: Failed to bind socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 521, __func__ , "mDNS-IPv6: Failed to bind socket: %m") : -abs(_e); }); | ||||
| 522 | goto fail; | ||||
| 523 | } | ||||
| 524 | } else { | ||||
| 525 | /* enable SO_REUSEADDR for the case that the user really wants multiple mDNS responders */ | ||||
| 526 | r = setsockopt(m->mdns_ipv6_fd, SOL_SOCKET1, SO_REUSEADDR2, &one, sizeof(one)); | ||||
| 527 | if (r < 0) { | ||||
| 528 | r = log_error_errno(errno, "mDNS-IPv6: Failed to set SO_REUSEADDR: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/resolve/resolved-mdns.c", 528, __func__ , "mDNS-IPv6: Failed to set SO_REUSEADDR: %m") : -abs(_e); }); | ||||
| 529 | goto fail; | ||||
| 530 | } | ||||
| 531 | } | ||||
| 532 | |||||
| 533 | r = sd_event_add_io(m->event, &m->mdns_ipv6_event_source, m->mdns_ipv6_fd, EPOLLINEPOLLIN, on_mdns_packet, m); | ||||
| 534 | if (r < 0) | ||||
| 535 | goto fail; | ||||
| 536 | |||||
| 537 | return m->mdns_ipv6_fd; | ||||
| 538 | |||||
| 539 | fail: | ||||
| 540 | m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); | ||||
| 541 | return r; | ||||
| 542 | } |
| 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 | }) |