]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-dns-stub.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolved-dns-stub.c
index 292e94daa3de637a0468ea26522f1a3a612241d8..5ce8d240ddc3167d0a248857f4601be0ed65ebb1 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -30,9 +31,12 @@ static int manager_dns_stub_tcp_fd(Manager *m);
 
 static int dns_stub_make_reply_packet(
                 DnsPacket **p,
+                size_t max_size,
                 DnsQuestion *q,
-                DnsAnswer *answer) {
+                DnsAnswer *answer,
+                bool *ret_truncated) {
 
+        bool truncated = false;
         DnsResourceRecord *rr;
         unsigned c = 0;
         int r;
@@ -43,7 +47,7 @@ static int dns_stub_make_reply_packet(
          * roundtrips aren't expensive. */
 
         if (!*p) {
-                r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0);
+                r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
                 if (r < 0)
                         return r;
 
@@ -71,12 +75,21 @@ static int dns_stub_make_reply_packet(
                 continue;
         add:
                 r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
+                if (r == -EMSGSIZE) {
+                        truncated = true;
+                        break;
+                }
                 if (r < 0)
                         return r;
 
                 c++;
         }
 
+        if (ret_truncated)
+                *ret_truncated = truncated;
+        else if (truncated)
+                return -EMSGSIZE;
+
         DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
 
         return 0;
@@ -86,6 +99,7 @@ static int dns_stub_finish_reply_packet(
                 DnsPacket *p,
                 uint16_t id,
                 int rcode,
+                bool tc,        /* set the Truncated bit? */
                 bool add_opt,   /* add an OPT RR to this packet? */
                 bool edns0_do,  /* set the EDNS0 DNSSEC OK bit? */
                 bool ad) {      /* set the DNSSEC authenticated data bit? */
@@ -110,14 +124,14 @@ static int dns_stub_finish_reply_packet(
         DNS_PACKET_HEADER(p)->id = id;
 
         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
-                                                              1 /* qr */,
-                                                              0 /* opcode */,
-                                                              0 /* aa */,
-                                                              0 /* tc */,
-                                                              1 /* rd */,
-                                                              1 /* ra */,
+                                                              1  /* qr */,
+                                                              0  /* opcode */,
+                                                              0  /* aa */,
+                                                              tc /* tc */,
+                                                              1  /* rd */,
+                                                              1  /* ra */,
                                                               ad /* ad */,
-                                                              0 /* cd */,
+                                                              0  /* cd */,
                                                               rcode));
 
         if (add_opt) {
@@ -149,12 +163,6 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl
         else {
                 int fd;
 
-                /* Truncate the message to the right size */
-                if (reply->size > DNS_PACKET_PAYLOAD_SIZE_MAX(p)) {
-                        dns_packet_truncate(reply, DNS_PACKET_UNICAST_SIZE_MAX);
-                        DNS_PACKET_HEADER(reply)->flags = htobe16(be16toh(DNS_PACKET_HEADER(reply)->flags) | DNS_PACKET_FLAG_TC);
-                }
-
                 fd = manager_dns_stub_udp_fd(m);
                 if (fd < 0)
                         return log_debug_errno(fd, "Failed to get reply socket: %m");
@@ -178,11 +186,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco
         assert(m);
         assert(p);
 
-        r = dns_stub_make_reply_packet(&reply, p->question, NULL);
+        r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
         if (r < 0)
                 return log_debug_errno(r, "Failed to make failure packet: %m");
 
-        r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), authenticated);
+        r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated);
         if (r < 0)
                 return log_debug_errno(r, "Failed to build failure packet: %m");
 
@@ -197,9 +205,10 @@ static void dns_stub_query_complete(DnsQuery *q) {
 
         switch (q->state) {
 
-        case DNS_TRANSACTION_SUCCESS:
+        case DNS_TRANSACTION_SUCCESS: {
+                bool truncated;
 
-                r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer);
+                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);
                 if (r < 0) {
                         log_debug_errno(r, "Failed to build reply packet: %m");
                         break;
@@ -221,6 +230,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
                                 q->reply_dns_packet,
                                 DNS_PACKET_ID(q->request_dns_packet),
                                 q->answer_rcode,
+                                truncated,
                                 !!q->request_dns_packet->opt,
                                 DNS_PACKET_DO(q->request_dns_packet),
                                 dns_query_fully_authenticated(q));
@@ -231,6 +241,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
 
                 (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
                 break;
+        }
 
         case DNS_TRANSACTION_RCODE_FAILURE:
                 (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));