LCOV - code coverage report
Current view: top level - resolve - resolved-dns-stub.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 318 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 14 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 264 0.0 %

           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 : }

Generated by: LCOV version 1.14