]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-stub.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolved-dns-stub.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b30bf55d
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include "fd-util.h"
22#include "resolved-dns-stub.h"
23#include "socket-util.h"
24
25/* The MTU of the loopback device is 64K on Linux, advertise that as maximum datagram size, but subtract the Ethernet,
26 * IP and UDP header sizes */
27#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
28
424e490b
ZJS
29static int manager_dns_stub_udp_fd(Manager *m);
30static int manager_dns_stub_tcp_fd(Manager *m);
31
b30bf55d 32static int dns_stub_make_reply_packet(
e8d23f92 33 DnsPacket **p,
51027656 34 size_t max_size,
b30bf55d 35 DnsQuestion *q,
51027656
LP
36 DnsAnswer *answer,
37 bool *ret_truncated) {
b30bf55d 38
51027656 39 bool truncated = false;
b30bf55d
LP
40 DnsResourceRecord *rr;
41 unsigned c = 0;
42 int r;
43
e8d23f92
LP
44 assert(p);
45
b30bf55d
LP
46 /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
47 * roundtrips aren't expensive. */
48
e8d23f92 49 if (!*p) {
51027656 50 r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
e8d23f92
LP
51 if (r < 0)
52 return r;
b30bf55d 53
e8d23f92
LP
54 r = dns_packet_append_question(*p, q);
55 if (r < 0)
56 return r;
b30bf55d 57
e8d23f92
LP
58 DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q));
59 }
b30bf55d
LP
60
61 DNS_ANSWER_FOREACH(rr, answer) {
e8d23f92 62
b30bf55d
LP
63 r = dns_question_matches_rr(q, rr, NULL);
64 if (r < 0)
65 return r;
66 if (r > 0)
67 goto add;
68
69 r = dns_question_matches_cname_or_dname(q, rr, NULL);
70 if (r < 0)
71 return r;
72 if (r > 0)
73 goto add;
74
75 continue;
76 add:
01c901e2 77 r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
51027656
LP
78 if (r == -EMSGSIZE) {
79 truncated = true;
80 break;
81 }
b30bf55d
LP
82 if (r < 0)
83 return r;
84
85 c++;
86 }
e8d23f92 87
51027656
LP
88 if (ret_truncated)
89 *ret_truncated = truncated;
90 else if (truncated)
91 return -EMSGSIZE;
92
e8d23f92
LP
93 DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
94
95 return 0;
96}
97
98static int dns_stub_finish_reply_packet(
99 DnsPacket *p,
100 uint16_t id,
101 int rcode,
51027656 102 bool tc, /* set the Truncated bit? */
e8d23f92
LP
103 bool add_opt, /* add an OPT RR to this packet? */
104 bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
105 bool ad) { /* set the DNSSEC authenticated data bit? */
106
107 int r;
108
109 assert(p);
110
941dd294
LP
111 if (!add_opt) {
112 /* If the client can't to EDNS0, don't do DO either */
113 edns0_do = false;
114
115 /* If the client didn't do EDNS, clamp the rcode to 4 bit */
116 if (rcode > 0xF)
117 rcode = DNS_RCODE_SERVFAIL;
118 }
119
120 /* Don't set the AD bit unless DO is on, too */
121 if (!edns0_do)
122 ad = false;
e8d23f92
LP
123
124 DNS_PACKET_HEADER(p)->id = id;
125
126 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
51027656
LP
127 1 /* qr */,
128 0 /* opcode */,
129 0 /* aa */,
130 tc /* tc */,
131 1 /* rd */,
132 1 /* ra */,
e8d23f92 133 ad /* ad */,
51027656 134 0 /* cd */,
e8d23f92 135 rcode));
b30bf55d
LP
136
137 if (add_opt) {
138 r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
139 if (r < 0)
140 return r;
141 }
142
b30bf55d
LP
143 return 0;
144}
145
146static void dns_stub_detach_stream(DnsStream *s) {
147 assert(s);
148
149 s->complete = NULL;
150 s->on_packet = NULL;
151 s->query = NULL;
152}
153
154static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *reply) {
155 int r;
156
157 assert(m);
158 assert(p);
159 assert(reply);
160
161 if (s)
162 r = dns_stream_write_packet(s, reply);
163 else {
164 int fd;
165
b30bf55d
LP
166 fd = manager_dns_stub_udp_fd(m);
167 if (fd < 0)
168 return log_debug_errno(fd, "Failed to get reply socket: %m");
169
170 /* Note that it is essential here that we explicitly choose the source IP address for this packet. This
171 * is because otherwise the kernel will choose it automatically based on the routing table and will
172 * thus pick 127.0.0.1 rather than 127.0.0.53. */
173
174 r = manager_send(m, fd, LOOPBACK_IFINDEX, p->family, &p->sender, p->sender_port, &p->destination, reply);
175 }
176 if (r < 0)
177 return log_debug_errno(r, "Failed to send reply packet: %m");
178
179 return 0;
180}
181
2b2d98c1 182static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rcode, bool authenticated) {
b30bf55d
LP
183 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
184 int r;
185
186 assert(m);
187 assert(p);
188
51027656 189 r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
e8d23f92
LP
190 if (r < 0)
191 return log_debug_errno(r, "Failed to make failure packet: %m");
192
51027656 193 r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated);
b30bf55d
LP
194 if (r < 0)
195 return log_debug_errno(r, "Failed to build failure packet: %m");
196
197 return dns_stub_send(m, s, p, reply);
198}
199
200static void dns_stub_query_complete(DnsQuery *q) {
201 int r;
202
203 assert(q);
204 assert(q->request_dns_packet);
205
206 switch (q->state) {
207
51027656
LP
208 case DNS_TRANSACTION_SUCCESS: {
209 bool truncated;
e8d23f92 210
51027656 211 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);
e8d23f92
LP
212 if (r < 0) {
213 log_debug_errno(r, "Failed to build reply packet: %m");
214 break;
215 }
b30bf55d 216
e8d23f92
LP
217 r = dns_query_process_cname(q);
218 if (r == -ELOOP) {
2b2d98c1 219 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
e8d23f92
LP
220 break;
221 }
222 if (r < 0) {
223 log_debug_errno(r, "Failed to process CNAME: %m");
224 break;
225 }
226 if (r == DNS_QUERY_RESTARTED)
227 return;
228
229 r = dns_stub_finish_reply_packet(
230 q->reply_dns_packet,
b30bf55d
LP
231 DNS_PACKET_ID(q->request_dns_packet),
232 q->answer_rcode,
51027656 233 truncated,
b30bf55d
LP
234 !!q->request_dns_packet->opt,
235 DNS_PACKET_DO(q->request_dns_packet),
941dd294 236 dns_query_fully_authenticated(q));
b30bf55d 237 if (r < 0) {
e8d23f92 238 log_debug_errno(r, "Failed to finish reply packet: %m");
b30bf55d
LP
239 break;
240 }
241
e8d23f92 242 (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
b30bf55d 243 break;
51027656 244 }
b30bf55d
LP
245
246 case DNS_TRANSACTION_RCODE_FAILURE:
2b2d98c1 247 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));
b30bf55d
LP
248 break;
249
250 case DNS_TRANSACTION_NOT_FOUND:
2b2d98c1 251 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_NXDOMAIN, dns_query_fully_authenticated(q));
b30bf55d
LP
252 break;
253
254 case DNS_TRANSACTION_TIMEOUT:
255 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
256 /* Propagate a timeout as a no packet, i.e. that the client also gets a timeout */
257 break;
258
259 case DNS_TRANSACTION_NO_SERVERS:
260 case DNS_TRANSACTION_INVALID_REPLY:
261 case DNS_TRANSACTION_ERRNO:
262 case DNS_TRANSACTION_ABORTED:
263 case DNS_TRANSACTION_DNSSEC_FAILED:
264 case DNS_TRANSACTION_NO_TRUST_ANCHOR:
265 case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
266 case DNS_TRANSACTION_NETWORK_DOWN:
2b2d98c1 267 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
b30bf55d
LP
268 break;
269
270 case DNS_TRANSACTION_NULL:
271 case DNS_TRANSACTION_PENDING:
272 case DNS_TRANSACTION_VALIDATING:
273 default:
274 assert_not_reached("Impossible state");
275 }
276
277 /* If there's a packet to write set, let's leave the stream around */
278 if (q->request_dns_stream && DNS_STREAM_QUEUED(q->request_dns_stream)) {
279
280 /* Detach the stream from our query (make it an orphan), but do not drop the reference to it. The
281 * default completion action of the stream will drop the reference. */
282
283 dns_stub_detach_stream(q->request_dns_stream);
284 q->request_dns_stream = NULL;
285 }
286
287 dns_query_free(q);
288}
289
290static int dns_stub_stream_complete(DnsStream *s, int error) {
291 assert(s);
292
293 log_debug_errno(error, "DNS TCP connection terminated, destroying query: %m");
294
295 assert(s->query);
296 dns_query_free(s->query);
297
298 return 0;
299}
300
301static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
302 DnsQuery *q = NULL;
303 int r;
304
305 assert(m);
306 assert(p);
307 assert(p->protocol == DNS_PROTOCOL_DNS);
308
309 /* Takes ownership of the *s stream object */
310
311 if (in_addr_is_localhost(p->family, &p->sender) <= 0 ||
312 in_addr_is_localhost(p->family, &p->destination) <= 0) {
313 log_error("Got packet on unexpected IP range, refusing.");
2b2d98c1 314 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
b30bf55d
LP
315 goto fail;
316 }
317
318 r = dns_packet_extract(p);
319 if (r < 0) {
320 log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m");
2b2d98c1 321 dns_stub_send_failure(m, s, p, DNS_RCODE_FORMERR, false);
b30bf55d
LP
322 goto fail;
323 }
324
325 if (!DNS_PACKET_VERSION_SUPPORTED(p)) {
326 log_debug("Got EDNS OPT field with unsupported version number.");
2b2d98c1 327 dns_stub_send_failure(m, s, p, DNS_RCODE_BADVERS, false);
b30bf55d
LP
328 goto fail;
329 }
330
331 if (dns_type_is_obsolete(p->question->keys[0]->type)) {
332 log_debug("Got message with obsolete key type, refusing.");
2b2d98c1 333 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
b30bf55d
LP
334 goto fail;
335 }
336
337 if (dns_type_is_zone_transer(p->question->keys[0]->type)) {
338 log_debug("Got request for zone transfer, refusing.");
2b2d98c1 339 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
b30bf55d
LP
340 goto fail;
341 }
342
343 if (!DNS_PACKET_RD(p)) {
344 /* If the "rd" bit is off (i.e. recursion was not requested), then refuse operation */
345 log_debug("Got request with recursion disabled, refusing.");
2b2d98c1 346 dns_stub_send_failure(m, s, p, DNS_RCODE_REFUSED, false);
b30bf55d
LP
347 goto fail;
348 }
349
350 if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) {
351 log_debug("Got request with DNSSEC CD bit set, refusing.");
2b2d98c1 352 dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
b30bf55d
LP
353 goto fail;
354 }
355
e8d23f92 356 r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH);
b30bf55d
LP
357 if (r < 0) {
358 log_error_errno(r, "Failed to generate query object: %m");
2b2d98c1 359 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
b30bf55d
LP
360 goto fail;
361 }
362
363 /* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */
364 q->clamp_ttl = true;
365
366 q->request_dns_packet = dns_packet_ref(p);
367 q->request_dns_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */
368 q->complete = dns_stub_query_complete;
369
370 if (s) {
371 s->on_packet = NULL;
372 s->complete = dns_stub_stream_complete;
373 s->query = q;
374 }
375
376 r = dns_query_go(q);
377 if (r < 0) {
378 log_error_errno(r, "Failed to start query: %m");
2b2d98c1 379 dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
b30bf55d
LP
380 goto fail;
381 }
382
52e63427 383 log_debug("Processing query...");
b30bf55d
LP
384 return;
385
386fail:
387 if (s && DNS_STREAM_QUEUED(s))
388 dns_stub_detach_stream(s);
389
390 dns_query_free(q);
391}
392
393static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
394 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
395 Manager *m = userdata;
396 int r;
397
398 r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
399 if (r <= 0)
400 return r;
401
402 if (dns_packet_validate_query(p) > 0) {
403 log_debug("Got DNS stub UDP query packet for id %u", DNS_PACKET_ID(p));
404
405 dns_stub_process_query(m, NULL, p);
406 } else
407 log_debug("Invalid DNS stub UDP packet, ignoring.");
408
409 return 0;
410}
411
424e490b 412static int manager_dns_stub_udp_fd(Manager *m) {
b30bf55d 413 static const int one = 1;
b30bf55d
LP
414 union sockaddr_union sa = {
415 .in.sin_family = AF_INET,
416 .in.sin_port = htobe16(53),
417 .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
418 };
424e490b 419 _cleanup_close_ int fd = -1;
b30bf55d
LP
420 int r;
421
422 if (m->dns_stub_udp_fd >= 0)
423 return m->dns_stub_udp_fd;
424
424e490b
ZJS
425 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
426 if (fd < 0)
b30bf55d
LP
427 return -errno;
428
424e490b
ZJS
429 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) < 0)
430 return -errno;
b30bf55d 431
424e490b
ZJS
432 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof one) < 0)
433 return -errno;
b30bf55d 434
424e490b
ZJS
435 if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof one) < 0)
436 return -errno;
b30bf55d
LP
437
438 /* Make sure no traffic from outside the local host can leak to onto this socket */
424e490b
ZJS
439 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0)
440 return -errno;
b30bf55d 441
424e490b
ZJS
442 if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
443 return -errno;
b30bf55d 444
424e490b 445 r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
b30bf55d 446 if (r < 0)
424e490b 447 return r;
b30bf55d
LP
448
449 (void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp");
424e490b
ZJS
450 m->dns_stub_udp_fd = fd;
451 fd = -1;
b30bf55d
LP
452
453 return m->dns_stub_udp_fd;
b30bf55d
LP
454}
455
456static int on_dns_stub_stream_packet(DnsStream *s) {
457 assert(s);
458 assert(s->read_packet);
459
460 if (dns_packet_validate_query(s->read_packet) > 0) {
461 log_debug("Got DNS stub TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
462
463 dns_stub_process_query(s->manager, s, s->read_packet);
464 } else
465 log_debug("Invalid DNS stub TCP packet, ignoring.");
466
467 /* Drop the reference to the stream. Either a query was created and added its own reference to the stream now,
468 * or that didn't happen in which case we want to free the stream */
469 dns_stream_unref(s);
470
471 return 0;
472}
473
474static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
475 DnsStream *stream;
476 Manager *m = userdata;
477 int cfd, r;
478
479 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
480 if (cfd < 0) {
3742095b 481 if (IN_SET(errno, EAGAIN, EINTR))
b30bf55d
LP
482 return 0;
483
484 return -errno;
485 }
486
487 r = dns_stream_new(m, &stream, DNS_PROTOCOL_DNS, cfd);
488 if (r < 0) {
489 safe_close(cfd);
490 return r;
491 }
492
493 stream->on_packet = on_dns_stub_stream_packet;
494
495 /* We let the reference to the stream dangling here, it will either be dropped by the default "complete" action
496 * of the stream, or by our packet callback, or when the manager is shut down. */
497
498 return 0;
499}
500
424e490b 501static int manager_dns_stub_tcp_fd(Manager *m) {
b30bf55d 502 static const int one = 1;
b30bf55d
LP
503 union sockaddr_union sa = {
504 .in.sin_family = AF_INET,
505 .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
506 .in.sin_port = htobe16(53),
507 };
424e490b 508 _cleanup_close_ int fd = -1;
b30bf55d
LP
509 int r;
510
511 if (m->dns_stub_tcp_fd >= 0)
512 return m->dns_stub_tcp_fd;
513
424e490b
ZJS
514 fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
515 if (fd < 0)
b30bf55d
LP
516 return -errno;
517
424e490b
ZJS
518 if (setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof one) < 0)
519 return -errno;
b30bf55d 520
424e490b
ZJS
521 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) < 0)
522 return -errno;
b30bf55d 523
424e490b
ZJS
524 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof one) < 0)
525 return -errno;
b30bf55d 526
424e490b
ZJS
527 if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof one) < 0)
528 return -errno;
b30bf55d
LP
529
530 /* Make sure no traffic from outside the local host can leak to onto this socket */
424e490b
ZJS
531 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0)
532 return -errno;
b30bf55d 533
424e490b
ZJS
534 if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
535 return -errno;
b30bf55d 536
424e490b
ZJS
537 if (listen(fd, SOMAXCONN) < 0)
538 return -errno;
b30bf55d 539
424e490b 540 r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, fd, EPOLLIN, on_dns_stub_stream, m);
b30bf55d 541 if (r < 0)
424e490b 542 return r;
b30bf55d
LP
543
544 (void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp");
424e490b
ZJS
545 m->dns_stub_tcp_fd = fd;
546 fd = -1;
b30bf55d
LP
547
548 return m->dns_stub_tcp_fd;
b30bf55d
LP
549}
550
551int manager_dns_stub_start(Manager *m) {
424e490b 552 const char *t = "UDP";
01b0669e 553 int r = 0;
b30bf55d
LP
554
555 assert(m);
556
d5da7707
ZJS
557 if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO)
558 log_debug("Not creating stub listener.");
559 else
560 log_debug("Creating stub listener using %s.",
561 m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
562 m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
563 "UDP/TCP");
564
424e490b 565 if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP))
1ae43295 566 r = manager_dns_stub_udp_fd(m);
b30bf55d 567
424e490b
ZJS
568 if (r >= 0 &&
569 IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_TCP)) {
570 t = "TCP";
1ae43295 571 r = manager_dns_stub_tcp_fd(m);
1ae43295 572 }
b30bf55d 573
0f4db364
ZJS
574 if (IN_SET(r, -EADDRINUSE, -EPERM)) {
575 if (r == -EADDRINUSE)
576 log_warning_errno(r,
577 "Another process is already listening on %s socket 127.0.0.53:53.\n"
578 "Turning off local DNS stub support.", t);
579 else
580 log_warning_errno(r,
581 "Failed to listen on %s socket 127.0.0.53:53: %m.\n"
582 "Turning off local DNS stub support.", t);
424e490b
ZJS
583 manager_dns_stub_stop(m);
584 } else if (r < 0)
585 return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
b30bf55d
LP
586
587 return 0;
588}
589
590void manager_dns_stub_stop(Manager *m) {
591 assert(m);
592
593 m->dns_stub_udp_event_source = sd_event_source_unref(m->dns_stub_udp_event_source);
594 m->dns_stub_tcp_event_source = sd_event_source_unref(m->dns_stub_tcp_event_source);
595
596 m->dns_stub_udp_fd = safe_close(m->dns_stub_udp_fd);
597 m->dns_stub_tcp_fd = safe_close(m->dns_stub_tcp_fd);
598}