diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-07-16 18:04:14 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-07-16 18:04:14 +0200 |
commit | c73ce96b569e2f10dff64b7dc0bd271972674c2a (patch) | |
tree | 2b1f464ae35e99a5954fccea5efb25512c0c53c4 /src | |
parent | 3cb10d3a0b1b6a7c44f307f2abb5215104e16941 (diff) |
dns-packet: allow dynamic resizing of DNS packets
Diffstat (limited to 'src')
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 43 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.h | 7 |
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) { |