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