]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-dns-scope.c
resolved: respond to local resolver requests on 127.0.0.53:53
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
index 66e4585c18794f30f8b26fcc75d330e7c0800b74..ed0c6aa10589a8e6e452f9fb105d3b01d4f1b2c9 100644 (file)
@@ -232,7 +232,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) {
                 if (fd < 0)
                         return fd;
 
-                r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, p);
+                r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, NULL, p);
                 if (r < 0)
                         return r;
 
@@ -257,7 +257,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) {
                 if (fd < 0)
                         return fd;
 
-                r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, p);
+                r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, NULL, p);
                 if (r < 0)
                         return r;
 
@@ -307,7 +307,7 @@ static int dns_scope_socket(
         union sockaddr_union sa = {};
         socklen_t salen;
         static const int one = 1;
-        int ret, r;
+        int ret, r, ifindex;
 
         assert(s);
 
@@ -315,6 +315,8 @@ static int dns_scope_socket(
                 assert(family == AF_UNSPEC);
                 assert(!address);
 
+                ifindex = dns_server_ifindex(server);
+
                 sa.sa.sa_family = server->family;
                 if (server->family == AF_INET) {
                         sa.in.sin_port = htobe16(port);
@@ -323,7 +325,7 @@ static int dns_scope_socket(
                 } else if (server->family == AF_INET6) {
                         sa.in6.sin6_port = htobe16(port);
                         sa.in6.sin6_addr = server->address.in6;
-                        sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
+                        sa.in6.sin6_scope_id = ifindex;
                         salen = sizeof(sa.in6);
                 } else
                         return -EAFNOSUPPORT;
@@ -332,6 +334,7 @@ static int dns_scope_socket(
                 assert(address);
 
                 sa.sa.sa_family = family;
+                ifindex = s->link ? s->link->ifindex : 0;
 
                 if (family == AF_INET) {
                         sa.in.sin_port = htobe16(port);
@@ -340,7 +343,7 @@ static int dns_scope_socket(
                 } else if (family == AF_INET6) {
                         sa.in6.sin6_port = htobe16(port);
                         sa.in6.sin6_addr = address->in6;
-                        sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
+                        sa.in6.sin6_scope_id = ifindex;
                         salen = sizeof(sa.in6);
                 } else
                         return -EAFNOSUPPORT;
@@ -357,14 +360,14 @@ static int dns_scope_socket(
         }
 
         if (s->link) {
-                uint32_t ifindex = htobe32(s->link->ifindex);
+                be32_t ifindex_be = htobe32(ifindex);
 
                 if (sa.sa.sa_family == AF_INET) {
-                        r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
+                        r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
                         if (r < 0)
                                 return -errno;
                 } else if (sa.sa.sa_family == AF_INET6) {
-                        r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
+                        r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
                         if (r < 0)
                                 return -errno;
                 }
@@ -575,6 +578,7 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in
 }
 
 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
+        assert(s);
 
         if (s->protocol != DNS_PROTOCOL_LLMNR)
                 return 0;
@@ -583,6 +587,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
 }
 
 int dns_scope_mdns_membership(DnsScope *s, bool b) {
+        assert(s);
 
         if (s->protocol != DNS_PROTOCOL_MDNS)
                 return 0;
@@ -601,15 +606,14 @@ static int dns_scope_make_reply_packet(
                 DnsPacket **ret) {
 
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        unsigned i;
         int r;
 
         assert(s);
         assert(ret);
 
-        if ((!q || q->n_keys <= 0)
-            && (!answer || answer->n_rrs <= 0)
-            && (!soa || soa->n_rrs <= 0))
+        if (dns_question_isempty(q) &&
+            dns_answer_isempty(answer) &&
+            dns_answer_isempty(soa))
                 return -EINVAL;
 
         r = dns_packet_new(&p, s->protocol, 0);
@@ -628,35 +632,20 @@ static int dns_scope_make_reply_packet(
                                                               0 /* (cd) */,
                                                               rcode));
 
-        if (q) {
-                for (i = 0; i < q->n_keys; i++) {
-                        r = dns_packet_append_key(p, q->keys[i], NULL);
-                        if (r < 0)
-                                return r;
-                }
-
-                DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
-        }
-
-        if (answer) {
-                for (i = 0; i < answer->n_rrs; i++) {
-                        r = dns_packet_append_rr(p, answer->items[i].rr, NULL, NULL);
-                        if (r < 0)
-                                return r;
-                }
-
-                DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
-        }
+        r = dns_packet_append_question(p, q);
+        if (r < 0)
+                return r;
+        DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
 
-        if (soa) {
-                for (i = 0; i < soa->n_rrs; i++) {
-                        r = dns_packet_append_rr(p, soa->items[i].rr, NULL, NULL);
-                        if (r < 0)
-                                return r;
-                }
+        r = dns_packet_append_answer(p, answer);
+        if (r < 0)
+                return r;
+        DNS_PACKET_HEADER(p)->ancount = htobe16(dns_answer_size(answer));
 
-                DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
-        }
+        r = dns_packet_append_answer(p, soa);
+        if (r < 0)
+                return r;
+        DNS_PACKET_HEADER(p)->arcount = htobe16(dns_answer_size(soa));
 
         *ret = p;
         p = NULL;
@@ -665,25 +654,25 @@ static int dns_scope_make_reply_packet(
 }
 
 static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
-        unsigned n;
+        DnsResourceRecord *rr;
+        DnsResourceKey *key;
 
         assert(s);
         assert(p);
 
-        if (p->question)
-                for (n = 0; n < p->question->n_keys; n++)
-                        dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
-        if (p->answer)
-                for (n = 0; n < p->answer->n_rrs; n++)
-                        dns_zone_verify_conflicts(&s->zone, p->answer->items[n].rr->key);
+        DNS_QUESTION_FOREACH(key, p->question)
+                dns_zone_verify_conflicts(&s->zone, key);
+
+        DNS_ANSWER_FOREACH(rr, p->answer)
+                dns_zone_verify_conflicts(&s->zone, rr->key);
 }
 
 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
-        _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
+        _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
         DnsResourceKey *key = NULL;
         bool tentative = false;
-        int r, fd;
+        int r;
 
         assert(s);
         assert(p);
@@ -705,7 +694,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
 
         r = dns_packet_extract(p);
         if (r < 0) {
-                log_debug_errno(r, "Failed to extract resources from incoming packet: %m");
+                log_debug_errno(r, "Failed to extract resource records from incoming packet: %m");
                 return;
         }
 
@@ -715,10 +704,10 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
                 return;
         }
 
-        assert(p->question->n_keys == 1);
+        assert(dns_question_size(p->question) == 1);
         key = p->question->keys[0];
 
-        r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative);
+        r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
         if (r < 0) {
                 log_debug_errno(r, "Failed to lookup key: %m");
                 return;
@@ -735,9 +724,21 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
                 return;
         }
 
-        if (stream)
+        if (stream) {
                 r = dns_stream_write_packet(stream, reply);
-        else {
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to enqueue reply packet: %m");
+                        return;
+                }
+
+                /* Let's take an extra reference on this stream, so that it stays around after returning. The reference
+                 * will be dangling until the stream is disconnected, and the default completion handler of the stream
+                 * will then unref the stream and destroy it */
+                if (DNS_STREAM_QUEUED(stream))
+                        dns_stream_ref(stream);
+        } else {
+                int fd;
+
                 if (!ratelimit_test(&s->ratelimit))
                         return;
 
@@ -759,12 +760,11 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
                  * verified uniqueness for all records. Also see RFC
                  * 4795, Section 2.7 */
 
-                r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
-        }
-
-        if (r < 0) {
-                log_debug_errno(r, "Failed to send reply packet: %m");
-                return;
+                r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, NULL, reply);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to send reply packet: %m");
+                        return;
+                }
         }
 }
 
@@ -1026,3 +1026,12 @@ bool dns_scope_network_good(DnsScope *s) {
 
         return manager_routable(s->manager, AF_UNSPEC);
 }
+
+int dns_scope_ifindex(DnsScope *s) {
+        assert(s);
+
+        if (s->link)
+                return s->link->ifindex;
+
+        return 0;
+}