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