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