chiark / gitweb /
dns-packet: allow dynamic resizing of DNS packets
authorLennart Poettering <lennart@poettering.net>
Wed, 16 Jul 2014 16:04:14 +0000 (18:04 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 16 Jul 2014 16:04:14 +0000 (18:04 +0200)
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-packet.h

index 9aa0734..af296f6 100644 (file)
@@ -20,7 +20,7 @@
  ***/
 
 #include "utf8.h"
-
+#include "util.h"
 #include "resolved-dns-domain.h"
 #include "resolved-dns-packet.h"
 
@@ -38,6 +38,13 @@ int dns_packet_new(DnsPacket **ret, size_t mtu) {
         if (a < DNS_PACKET_HEADER_SIZE)
                 a = DNS_PACKET_HEADER_SIZE;
 
+        /* round up to next page size */
+        a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
+
+        /* make sure we never allocate more than useful */
+        if (a > DNS_PACKET_SIZE_MAX)
+                a = DNS_PACKET_SIZE_MAX;
+
         p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
         if (!p)
                 return -ENOMEM;
@@ -112,6 +119,9 @@ int dns_packet_validate(DnsPacket *p) {
         if (p->size < DNS_PACKET_HEADER_SIZE)
                 return -EBADMSG;
 
+        if (p->size > DNS_PACKET_SIZE_MAX)
+                return -EBADMSG;
+
         return 0;
 }
 
@@ -136,8 +146,35 @@ int dns_packet_validate_reply(DnsPacket *p) {
 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
         assert(p);
 
-        if (p->size + add > p->allocated)
-                return -ENOMEM;
+        if (p->size + add > p->allocated) {
+                size_t a;
+
+                a = PAGE_ALIGN((p->size + add) * 2);
+                if (a > DNS_PACKET_SIZE_MAX)
+                        a = DNS_PACKET_SIZE_MAX;
+
+                if (p->size + add > a)
+                        return -EMSGSIZE;
+
+                if (p->data) {
+                        void *d;
+
+                        d = realloc(p->data, a);
+                        if (!d)
+                                return -ENOMEM;
+
+                        p->data = d;
+                } else {
+                        p->data = malloc(a);
+                        if (!p->data)
+                                return -ENOMEM;
+
+                        memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
+                        memzero((uint8_t*) p->data + p->size, a - p->size);
+                }
+
+                p->allocated = a;
+        }
 
         if (start)
                 *start = p->size;
index 77edc05..10f8f96 100644 (file)
@@ -41,14 +41,19 @@ struct DnsPacketHeader {
 };
 
 #define DNS_PACKET_HEADER_SIZE sizeof(DnsPacketHeader)
+
+/* The various DNS protocols deviate in how large a packet can grow,
+   but the TCP transport has a 16bit size field, hence that appears to
+   be the maximum. */
+#define DNS_PACKET_SIZE_MAX 0xFFFF
 #define DNS_PACKET_SIZE_START 512
 
 struct DnsPacket {
         int n_ref;
+        int ifindex;
         size_t size, allocated, rindex;
         Hashmap *names; /* For name compression */
         void *data;
-        int ifindex;
 };
 
 static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) {