chiark / gitweb /
resolved: add API for resolving specific RRs
[elogind.git] / src / resolve / resolved-dns-scope.c
index 9a636b179c82ee3d3ebcae2ebf4e9516375a9458..5141a8d8047920a37c8e071848c8c0c6002f700b 100644 (file)
@@ -254,7 +254,7 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
         }
 
         if (s->protocol == DNS_PROTOCOL_LLMNR) {
-                /* RFC 4795, section 2.5 suggests the TTL to be set to 1 */
+                /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
 
                 if (sa.sa.sa_family == AF_INET) {
                         r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
@@ -312,8 +312,8 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
         }
 
         if (s->protocol == DNS_PROTOCOL_LLMNR) {
-                if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
-                    dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
+                if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
+                    dns_name_endswith(domain, "ip6.arpa") > 0 ||
                     dns_name_single_label(domain) > 0)
                         return DNS_SCOPE_MAYBE;
 
@@ -389,14 +389,14 @@ int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union
                 return !!manager_find_dns_server(s->manager, family, address);
 }
 
-static int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *a, DnsPacket **ret) {
+static int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, DnsPacket **ret) {
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
         unsigned i;
         int r;
 
         assert(s);
 
-        if (q->n_keys <= 0 && a->n_rrs <= 0)
+        if (q->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
                 return -EINVAL;
 
         r = dns_packet_new(&p, s->protocol, 0);
@@ -404,7 +404,16 @@ static int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQ
                 return r;
 
         DNS_PACKET_HEADER(p)->id = id;
-        DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, rcode));
+        DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
+                                                              1 /* qr */,
+                                                              0 /* opcode */,
+                                                              0 /* c */,
+                                                              0 /* tc */,
+                                                              0 /* t */,
+                                                              0 /* (ra) */,
+                                                              0 /* (ad) */,
+                                                              0 /* (cd) */,
+                                                              rcode));
 
         if (q) {
                 for (i = 0; i < q->n_keys; i++) {
@@ -416,14 +425,24 @@ static int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQ
                 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
         }
 
-        if (a) {
-                for (i = 0; i < a->n_rrs; i++) {
-                        r = dns_packet_append_rr(p, a->rrs[i], NULL);
+        if (answer) {
+                for (i = 0; i < answer->n_rrs; i++) {
+                        r = dns_packet_append_rr(p, answer->rrs[i], NULL);
                         if (r < 0)
                                 return r;
                 }
 
-                DNS_PACKET_HEADER(p)->ancount = htobe16(a->n_rrs);
+                DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
+        }
+
+        if (soa) {
+                for (i = 0; i < soa->n_rrs; i++) {
+                        r = dns_packet_append_rr(p, soa->rrs[i], NULL);
+                        if (r < 0)
+                                return r;
+                }
+
+                DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
         }
 
         *ret = p;
@@ -434,7 +453,7 @@ static int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQ
 
 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;
+        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
         int r, fd;
 
         assert(s);
@@ -443,13 +462,30 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
         if (p->protocol != DNS_PROTOCOL_LLMNR)
                 return;
 
+        if (p->ipproto == IPPROTO_UDP) {
+                /* Don't accept UDP queries directed to anything but
+                 * the LLMNR multicast addresses. See RFC 4795,
+                 * section 2.5.*/
+
+                if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
+                        return;
+
+                if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
+                        return;
+        }
+
         r = dns_packet_extract(p);
         if (r < 0) {
                 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
                 return;
         }
 
-        r = dns_zone_lookup(&s->zone, p->question, &answer);
+        if (DNS_PACKET_C(p)) {
+                /* FIXME: Somebody notified us about a likely conflict */
+                return;
+        }
+
+        r = dns_zone_lookup(&s->zone, p->question, &answer, &soa);
         if (r < 0) {
                 log_debug("Failed to lookup key: %s", strerror(-r));
                 return;
@@ -457,7 +493,9 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
         if (r == 0)
                 return;
 
-        r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, &reply);
+        dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
+
+        r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, &reply);
         if (r < 0) {
                 log_debug("Failed to build reply packet: %s", strerror(-r));
                 return;