summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-07-16 18:04:14 +0200
committerLennart Poettering <lennart@poettering.net>2014-07-16 18:04:14 +0200
commitc73ce96b569e2f10dff64b7dc0bd271972674c2a (patch)
tree2b1f464ae35e99a5954fccea5efb25512c0c53c4
parent3cb10d3a0b1b6a7c44f307f2abb5215104e16941 (diff)
dns-packet: allow dynamic resizing of DNS packets
-rw-r--r--src/resolve/resolved-dns-packet.c43
-rw-r--r--src/resolve/resolved-dns-packet.h7
2 files changed, 46 insertions, 4 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 9aa0734213..af296f63ac 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -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;
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 77edc05a19..10f8f96915 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -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) {