]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-stub.c
resolve: allow configurable bind address
[thirdparty/systemd.git] / src / resolve / resolved-dns-stub.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "errno-util.h"
4 #include "fd-util.h"
5 #include "missing_network.h"
6 #include "resolved-dns-stub.h"
7 #include "socket-netlink.h"
8 #include "socket-util.h"
9
10 /* The MTU of the loopback device is 64K on Linux, advertise that as maximum datagram size, but subtract the Ethernet,
11 * IP and UDP header sizes */
12 #define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
13
14 static int manager_dns_stub_udp_fd(Manager *m);
15 static int manager_dns_stub_tcp_fd(Manager *m);
16
17 int dns_stub_extra_new(DNSStubListenerExtra **ret) {
18 DNSStubListenerExtra *l;
19
20 l = new(DNSStubListenerExtra, 1);
21 if (!l)
22 return -ENOMEM;
23
24 *l = (DNSStubListenerExtra) {
25 .fd = -1,
26 };
27
28 *ret = TAKE_PTR(l);
29
30 return 0;
31 }
32
33 static int dns_stub_make_reply_packet(
34 DnsPacket **p,
35 size_t max_size,
36 DnsQuestion *q,
37 DnsAnswer *answer,
38 bool *ret_truncated) {
39
40 bool truncated = false;
41 DnsResourceRecord *rr;
42 unsigned c = 0;
43 int r;
44
45 assert(p);
46
47 /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
48 * roundtrips aren't expensive. */
49
50 if (!*p) {
51 r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
52 if (r < 0)
53 return r;
54
55 r = dns_packet_append_question(*p, q);
56 if (r < 0)
57 return r;
58
59 DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q));
60 }
61
62 DNS_ANSWER_FOREACH(rr, answer) {
63
64 r = dns_question_matches_rr(q, rr, NULL);
65 if (r < 0)
66 return r;
67 if (r > 0)
68 goto add;
69
70 r = dns_question_matches_cname_or_dname(q, rr, NULL);
71 if (r < 0)
72 return r;
73 if (r > 0)
74 goto add;
75
76 continue;
77 add:
78 r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
79 if (r == -EMSGSIZE) {
80 truncated = true;
81 break;
82 }
83 if (r < 0)
84 return r;
85
86 c++;
87 }
88
89 if (ret_truncated)
90 *ret_truncated = truncated;
91 else if (truncated)
92 return -EMSGSIZE;
93
94 DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
95
96 return 0;
97 }
98
99 static int dns_stub_finish_reply_packet(
100 DnsPacket *p,
101 uint16_t id,
102 int rcode,
103 bool tc, /* set the Truncated bit? */
104 bool add_opt, /* add an OPT RR to this packet? */
105 bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
106 bool ad) { /* set the DNSSEC authenticated data bit? */
107
108 int r;
109
110 assert(p);
111
112 if (add_opt) {
113 r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
114 if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */
115 tc = true;
116 else if (r < 0)
117 return r;
118
119 } else {
120 /* If the client can't to EDNS0, don't do DO either */
121 edns0_do = false;
122
123 /* If the client didn't do EDNS, clamp the rcode to 4 bit */
124 if (rcode > 0xF)
125 rcode = DNS_RCODE_SERVFAIL;
126 }
127
128 /* Don't set the AD bit unless DO is on, too */
129 if (!edns0_do)
130 ad = false;
131
132 DNS_PACKET_HEADER(p)->id = id;
133
134 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
135 1 /* qr */,
136 0 /* opcode */,
137 0 /* aa */,
138 tc /* tc */,
139 1 /* rd */,
140 1 /* ra */,
141 ad /* ad */,
142 0 /* cd */,
143 rcode));
144
145 return 0;
146 }
147
148 static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *reply) {
149 int r;
150
151 assert(m);
152 assert(p);
153 assert(reply);
154
155 if (s)
156 r = dns_stream_write_packet(s, reply);
157 else {
158 int fd;
159
160 fd = manager_dns_stub_udp_fd(m);
161 if (fd < 0)
162 return log_debug_errno(fd, "Failed to get reply socket: %m");
163
164 /* Note that it is essential here that we explicitly choose the source IP address for this packet. This
165 * is because otherwise the kernel will choose it automatically based on the routing table and will
166 * thus pick 127.0.0.1 rather than 127.0.0.53. */
167
168 r = manager_send(m, fd, LOOPBACK_IFINDEX, p->family, &p->sender, p->sender_port, &p->destination, reply);
169 }
170 if (r < 0)
171 return log_debug_errno(r, "Failed to send reply packet: %m");
172
173 return 0;
174 }
175
176 static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rcode, bool authenticated) {
177 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
178 int r;
179
180 assert(m);
181 assert(p);
182
183 r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
184 if (r < 0)
185 return log_debug_errno(r, "Failed to make failure packet: %m");
186
187 r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated);
188 if (r < 0)
189 return log_debug_errno(r, "Failed to build failure packet: %m");
190
191 return dns_stub_send(m, s, p, reply);
192 }
193
194 static void dns_stub_query_complete(DnsQuery *q) {
195 int r;
196
197 assert(q);
198 assert(q->request_dns_packet);
199
200 switch (q->state) {
201
202 case DNS_TRANSACTION_SUCCESS: {
203 bool truncated;
204
205 r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated);
206 if (r < 0) {
207 log_debug_errno(r, "Failed to build reply packet: %m");
208 break;
209 }
210
211 if (!truncated) {
212 r = dns_query_process_cname(q);
213 if (r == -ELOOP) {
214 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
215 break;
216 }
217 if (r < 0) {
218 log_debug_errno(r, "Failed to process CNAME: %m");
219 break;
220 }
221 if (r == DNS_QUERY_RESTARTED)
222 return;
223 }
224
225 r = dns_stub_finish_reply_packet(
226 q->reply_dns_packet,
227 DNS_PACKET_ID(q->request_dns_packet),
228 q->answer_rcode,
229 truncated,
230 !!q->request_dns_packet->opt,
231 DNS_PACKET_DO(q->request_dns_packet),
232 dns_query_fully_authenticated(q));
233 if (r < 0) {
234 log_debug_errno(r, "Failed to finish reply packet: %m");
235 break;
236 }
237
238 (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
239 break;
240 }
241
242 case DNS_TRANSACTION_RCODE_FAILURE:
243 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));
244 break;
245
246 case DNS_TRANSACTION_NOT_FOUND:
247 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_NXDOMAIN, dns_query_fully_authenticated(q));
248 break;
249
250 case DNS_TRANSACTION_TIMEOUT:
251 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
252 /* Propagate a timeout as a no packet, i.e. that the client also gets a timeout */
253 break;
254
255 case DNS_TRANSACTION_NO_SERVERS:
256 case DNS_TRANSACTION_INVALID_REPLY:
257 case DNS_TRANSACTION_ERRNO:
258 case DNS_TRANSACTION_ABORTED:
259 case DNS_TRANSACTION_DNSSEC_FAILED:
260 case DNS_TRANSACTION_NO_TRUST_ANCHOR:
261 case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
262 case DNS_TRANSACTION_NETWORK_DOWN:
263 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
264 break;
265
266 case DNS_TRANSACTION_NULL:
267 case DNS_TRANSACTION_PENDING:
268 case DNS_TRANSACTION_VALIDATING:
269 default:
270 assert_not_reached("Impossible state");
271 }
272
273 dns_query_free(q);
274 }
275
276 static int dns_stub_stream_complete(DnsStream *s, int error) {
277 assert(s);
278
279 log_debug_errno(error, "DNS TCP connection terminated, destroying queries: %m");
280
281 for (;;) {
282 DnsQuery *q;
283
284 q = set_first(s->queries);
285 if (!q)
286 break;
287
288 dns_query_free(q);
289 }
290
291 /* This drops the implicit ref we keep around since it was allocated, as incoming stub connections
292 * should be kept as long as the client wants to. */
293 dns_stream_unref(s);
294 return 0;
295 }
296
297 static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
298 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
299 int r;
300
301 assert(m);
302 assert(p);
303 assert(p->protocol == DNS_PROTOCOL_DNS);
304
305 if (in_addr_is_localhost(p->family, &p->sender) <= 0 ||
306 in_addr_is_localhost(p->family, &p->destination) <= 0) {
307 log_error("Got packet on unexpected IP range, refusing.");
308 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
309 return;
310 }
311
312 r = dns_packet_extract(p);
313 if (r < 0) {
314 log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m");
315 dns_stub_send_failure(m, s, p, DNS_RCODE_FORMERR, false);
316 return;
317 }
318
319 if (!DNS_PACKET_VERSION_SUPPORTED(p)) {
320 log_debug("Got EDNS OPT field with unsupported version number.");
321 dns_stub_send_failure(m, s, p, DNS_RCODE_BADVERS, false);
322 return;
323 }
324
325 if (dns_type_is_obsolete(p->question->keys[0]->type)) {
326 log_debug("Got message with obsolete key type, refusing.");
327 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
328 return;
329 }
330
331 if (dns_type_is_zone_transer(p->question->keys[0]->type)) {
332 log_debug("Got request for zone transfer, refusing.");
333 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
334 return;
335 }
336
337 if (!DNS_PACKET_RD(p)) {
338 /* If the "rd" bit is off (i.e. recursion was not requested), then refuse operation */
339 log_debug("Got request with recursion disabled, refusing.");
340 dns_stub_send_failure(m, s, p, DNS_RCODE_REFUSED, false);
341 return;
342 }
343
344 if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) {
345 log_debug("Got request with DNSSEC CD bit set, refusing.");
346 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
347 return;
348 }
349
350 r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH);
351 if (r < 0) {
352 log_error_errno(r, "Failed to generate query object: %m");
353 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
354 return;
355 }
356
357 /* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */
358 q->clamp_ttl = true;
359
360 q->request_dns_packet = dns_packet_ref(p);
361 q->request_dns_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */
362 q->complete = dns_stub_query_complete;
363
364 if (s) {
365 /* Remember which queries belong to this stream, so that we can cancel them when the stream
366 * is disconnected early */
367
368 r = set_ensure_put(&s->queries, NULL, q);
369 if (r < 0) {
370 log_oom();
371 return;
372 }
373 assert(r > 0);
374 }
375
376 r = dns_query_go(q);
377 if (r < 0) {
378 log_error_errno(r, "Failed to start query: %m");
379 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
380 return;
381 }
382
383 log_debug("Processing query...");
384 TAKE_PTR(q);
385 }
386
387 static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
388 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
389 Manager *m = userdata;
390 int r;
391
392 r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
393 if (r <= 0)
394 return r;
395
396 if (dns_packet_validate_query(p) > 0) {
397 log_debug("Got DNS stub UDP query packet for id %u", DNS_PACKET_ID(p));
398
399 dns_stub_process_query(m, NULL, p);
400 } else
401 log_debug("Invalid DNS stub UDP packet, ignoring.");
402
403 return 0;
404 }
405
406 static int set_dns_stub_common_socket_options(int fd) {
407 int r;
408
409 assert(fd >= 0);
410
411 r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
412 if (r < 0)
413 return r;
414
415 r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
416 if (r < 0)
417 return r;
418
419 return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
420 }
421
422 static int manager_dns_stub_udp_fd(Manager *m) {
423 union sockaddr_union sa = {
424 .in.sin_family = AF_INET,
425 .in.sin_port = htobe16(53),
426 .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
427 };
428 _cleanup_close_ int fd = -1;
429 int r;
430
431 if (m->dns_stub_udp_fd >= 0)
432 return m->dns_stub_udp_fd;
433
434 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
435 if (fd < 0)
436 return -errno;
437
438 r = set_dns_stub_common_socket_options(fd);
439 if (r < 0)
440 return r;
441
442 /* Make sure no traffic from outside the local host can leak to onto this socket */
443 r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
444 if (r < 0)
445 return r;
446
447 if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
448 return -errno;
449
450 r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
451 if (r < 0)
452 return r;
453
454 (void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp");
455
456 return m->dns_stub_udp_fd = TAKE_FD(fd);
457 }
458
459 static int manager_dns_stub_udp_fd_extra(Manager *m, DNSStubListenerExtra *l) {
460 _cleanup_free_ char *pretty = NULL;
461 _cleanup_close_ int fd = -1;
462 int r;
463
464 if (l->fd >= 0)
465 return 0;
466
467 fd = socket(socket_address_family(&l->address), SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
468 if (fd < 0) {
469 r = -errno;
470 goto fail;
471 }
472
473 r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
474 if (r < 0)
475 goto fail;
476
477 r = set_dns_stub_common_socket_options(fd);
478 if (r < 0)
479 goto fail;
480
481 if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) {
482 r = -errno;
483 goto fail;
484 }
485
486 r = sd_event_add_io(m->event, &l->dns_stub_extra_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
487 if (r < 0)
488 goto fail;
489
490 (void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-udp-extra");
491
492 l->fd = TAKE_FD(fd);
493
494 if (DEBUG_LOGGING) {
495 (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
496 log_debug("Listening on UDP socket %s.", strnull(pretty));
497 }
498
499 return 0;
500
501 fail:
502 (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
503 if (r == -EADDRINUSE)
504 return log_warning_errno(r,
505 "Another process is already listening on UDP socket %s.\n"
506 "Turning off local DNS stub extra support.", strnull(pretty));
507 if (r == -EPERM)
508 return log_warning_errno(r,
509 "Failed to listen on UDP socket %s: %m.\n"
510 "Turning off local DNS stub extra support.", strnull(pretty));
511
512 assert(r < 0);
513
514 return log_warning_errno(r, "Failed to listen on UDP socket %s, ignoring: %m", strnull(pretty));
515 }
516
517 static int on_dns_stub_stream_packet(DnsStream *s) {
518 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
519
520 assert(s);
521
522 p = dns_stream_take_read_packet(s);
523 assert(p);
524
525 if (dns_packet_validate_query(p) > 0) {
526 log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(p));
527
528 dns_stub_process_query(s->manager, s, p);
529 } else
530 log_debug("Invalid DNS stub TCP packet, ignoring.");
531
532 return 0;
533 }
534
535 static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
536 DnsStream *stream;
537 Manager *m = userdata;
538 int cfd, r;
539
540 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
541 if (cfd < 0) {
542 if (ERRNO_IS_ACCEPT_AGAIN(errno))
543 return 0;
544
545 return -errno;
546 }
547
548 r = dns_stream_new(m, &stream, DNS_STREAM_STUB, DNS_PROTOCOL_DNS, cfd, NULL);
549 if (r < 0) {
550 safe_close(cfd);
551 return r;
552 }
553
554 stream->on_packet = on_dns_stub_stream_packet;
555 stream->complete = dns_stub_stream_complete;
556
557 /* We let the reference to the stream dangle here, it will be dropped later by the complete callback. */
558
559 return 0;
560 }
561
562 static int manager_dns_stub_tcp_fd(Manager *m) {
563 union sockaddr_union sa = {
564 .in.sin_family = AF_INET,
565 .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
566 .in.sin_port = htobe16(53),
567 };
568 _cleanup_close_ int fd = -1;
569 int r;
570
571 if (m->dns_stub_tcp_fd >= 0)
572 return m->dns_stub_tcp_fd;
573
574 fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
575 if (fd < 0)
576 return -errno;
577
578 r = set_dns_stub_common_socket_options(fd);
579 if (r < 0)
580 return r;
581
582 r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, true);
583 if (r < 0)
584 return r;
585
586 /* Make sure no traffic from outside the local host can leak to onto this socket */
587 r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
588 if (r < 0)
589 return r;
590
591 if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
592 return -errno;
593
594 if (listen(fd, SOMAXCONN) < 0)
595 return -errno;
596
597 r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, fd, EPOLLIN, on_dns_stub_stream, m);
598 if (r < 0)
599 return r;
600
601 (void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp");
602
603 return m->dns_stub_tcp_fd = TAKE_FD(fd);
604 }
605
606 static int manager_dns_stub_tcp_fd_extra(Manager *m, DNSStubListenerExtra *l) {
607 _cleanup_free_ char *pretty = NULL;
608 _cleanup_close_ int fd = -1;
609 int r;
610
611 if (l->fd >= 0)
612 return 0;
613
614 fd = socket(socket_address_family(&l->address), SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
615 if (fd < 0) {
616 r = -errno;
617 goto fail;
618 }
619
620 r = set_dns_stub_common_socket_options(fd);
621 if (r < 0)
622 goto fail;
623
624 r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, true);
625 if (r < 0)
626 goto fail;
627
628 r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
629 if (r < 0)
630 goto fail;
631
632 if (bind(fd, &l->address.sockaddr.sa, l->address.size) < 0) {
633 r = -errno;
634 goto fail;
635 }
636
637 if (listen(fd, SOMAXCONN) < 0) {
638 r = -errno;
639 goto fail;
640 }
641
642 r = sd_event_add_io(m->event, &l->dns_stub_extra_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
643 if (r < 0)
644 goto fail;
645
646 (void) sd_event_source_set_description(l->dns_stub_extra_event_source, "dns-stub-tcp-extra");
647
648 l->fd = TAKE_FD(fd);
649
650 if (DEBUG_LOGGING) {
651 (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
652 log_debug("Listening on TCP socket %s.", strnull(pretty));
653 }
654
655 return 0;
656
657 fail:
658 (void) sockaddr_pretty(&l->address.sockaddr.sa, FAMILY_ADDRESS_SIZE(l->address.sockaddr.sa.sa_family), true, true, &pretty);
659 if (r == -EADDRINUSE)
660 return log_warning_errno(r,
661 "Another process is already listening on TCP socket %s.\n"
662 "Turning off local DNS stub extra support.", strnull(pretty));
663 if (r == -EPERM)
664 return log_warning_errno(r,
665 "Failed to listen on TCP socket %s: %m.\n"
666 "Turning off local DNS stub extra support.", strnull(pretty));
667
668 assert(r < 0);
669
670 return log_warning_errno(r, "Failed to listen on TCP socket %s, ignoring: %m", strnull(pretty));
671 }
672
673 int manager_dns_stub_start(Manager *m) {
674 const char *t = "UDP";
675 int r = 0;
676
677 assert(m);
678
679 if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO)
680 log_debug("Not creating stub listener.");
681 else
682 log_debug("Creating stub listener using %s.",
683 m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
684 m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
685 "UDP/TCP");
686
687 if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP))
688 r = manager_dns_stub_udp_fd(m);
689
690 if (r >= 0 &&
691 IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_TCP)) {
692 t = "TCP";
693 r = manager_dns_stub_tcp_fd(m);
694 }
695
696 if (IN_SET(r, -EADDRINUSE, -EPERM)) {
697 if (r == -EADDRINUSE)
698 log_warning_errno(r,
699 "Another process is already listening on %s socket 127.0.0.53:53.\n"
700 "Turning off local DNS stub support.", t);
701 else
702 log_warning_errno(r,
703 "Failed to listen on %s socket 127.0.0.53:53: %m.\n"
704 "Turning off local DNS stub support.", t);
705 manager_dns_stub_stop(m);
706 } else if (r < 0)
707 return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
708
709 if (!ordered_set_isempty(m->dns_extra_stub_listeners)) {
710 DNSStubListenerExtra *l;
711 Iterator i;
712
713 log_debug("Creating stub listener extra using %s.",
714 m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
715 m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
716 "UDP/TCP");
717
718 ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i)
719 if (l->mode == DNS_STUB_LISTENER_UDP)
720 (void) manager_dns_stub_udp_fd_extra(m, l);
721 else
722 (void) manager_dns_stub_tcp_fd_extra(m, l);
723 }
724
725 return 0;
726 }
727
728 void manager_dns_stub_stop(Manager *m) {
729 assert(m);
730
731 m->dns_stub_udp_event_source = sd_event_source_unref(m->dns_stub_udp_event_source);
732 m->dns_stub_tcp_event_source = sd_event_source_unref(m->dns_stub_tcp_event_source);
733
734 m->dns_stub_udp_fd = safe_close(m->dns_stub_udp_fd);
735 m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_fd);
736 }
737
738 void manager_dns_stub_stop_extra(Manager *m) {
739 DNSStubListenerExtra *l;
740 Iterator i;
741
742 assert(m);
743
744 ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners, i) {
745 l->dns_stub_extra_event_source = sd_event_source_unref(l->dns_stub_extra_event_source);
746 l->fd = safe_close(l->fd);
747 }
748 }