***/
#include "utf8.h"
-
+#include "util.h"
#include "resolved-dns-domain.h"
#include "resolved-dns-packet.h"
-int dns_packet_new(DnsPacket **ret, size_t mtu) {
+int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
DnsPacket *p;
size_t a;
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;
p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
p->allocated = a;
+ p->protocol = protocol;
p->n_ref = 1;
*ret = p;
return 0;
}
-int dns_packet_new_query(DnsPacket **ret, size_t mtu) {
+int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
DnsPacket *p;
DnsPacketHeader *h;
int r;
assert(ret);
- r = dns_packet_new(&p, mtu);
+ r = dns_packet_new(&p, protocol, mtu);
if (r < 0)
return r;
h = DNS_PACKET_HEADER(p);
- h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0));
+
+ if (protocol == DNS_PROTOCOL_DNS)
+ h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0)); /* ask for recursion */
+ else
+ h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0));
*ret = p;
return 0;
assert(p);
+ if (p->rrs)
+ dns_resource_record_freev(p->rrs, DNS_PACKET_RRCOUNT(p));
+
while ((s = hashmap_steal_first_key(p->names)))
free(s);
hashmap_free(p->names);
if (p->size < DNS_PACKET_HEADER_SIZE)
return -EBADMSG;
+ if (p->size > DNS_PACKET_SIZE_MAX)
+ return -EBADMSG;
+
return 0;
}
int dns_packet_validate_reply(DnsPacket *p) {
- DnsPacketHeader *h;
int r;
assert(p);
if (r < 0)
return r;
- h = DNS_PACKET_HEADER(p);
-
- /* Check QR field */
- if ((be16toh(h->flags) & 1) == 0)
+ if (DNS_PACKET_QR(p) == 0)
return -EBADMSG;
- /* Check opcode field */
- if (((be16toh(h->flags) >> 1) & 15) != 0)
+ if (DNS_PACKET_OPCODE(p) != 0)
return -EBADMSG;
return 0;
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;
return 0;
}
-static void dns_packet_rewind(DnsPacket *p, size_t idx) {
+void dns_packet_rewind(DnsPacket *p, size_t idx) {
assert(p);
assert(idx <= p->size);
assert(idx >= DNS_PACKET_HEADER_SIZE);
}
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
size_t saved_rindex, offset;
uint16_t rdlength;
const void *d;
assert(p);
assert(ret);
- saved_rindex = p->rindex;
-
rr = dns_resource_record_new();
if (!rr)
- goto fail;
+ return -ENOMEM;
+
+ saved_rindex = p->rindex;
r = dns_packet_read_key(p, &rr->key, NULL);
if (r < 0)
}
int dns_packet_skip_question(DnsPacket *p) {
+ unsigned i, n;
int r;
- unsigned i, n;
assert(p);
- n = be16toh(DNS_PACKET_HEADER(p)->qdcount);
+ dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
+
+ n = DNS_PACKET_QDCOUNT(p);
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_key_free) DnsResourceKey key = {};
return 0;
}
+int dns_packet_extract_rrs(DnsPacket *p) {
+ DnsResourceRecord **rrs = NULL;
+ size_t saved_rindex;
+ unsigned n, added = 0;
+ int r;
+
+ if (p->rrs)
+ return (int) DNS_PACKET_RRCOUNT(p);
+
+ saved_rindex = p->rindex;
+
+ r = dns_packet_skip_question(p);
+ if (r < 0)
+ goto finish;
+
+ n = DNS_PACKET_RRCOUNT(p);
+ if (n <= 0) {
+ r = 0;
+ goto finish;
+ }
+
+ rrs = new0(DnsResourceRecord*, n);
+ if (!rrs) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ for (added = 0; added < n; added++) {
+ r = dns_packet_read_rr(p, &rrs[added], NULL);
+ if (r < 0) {
+ dns_resource_record_freev(rrs, added);
+ goto finish;
+ }
+ }
+
+ p->rrs = rrs;
+ r = (int) n;
+
+finish:
+ p->rindex = saved_rindex;
+ return r;
+}
+
static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
[DNS_RCODE_SUCCESS] = "SUCCESS",
[DNS_RCODE_FORMERR] = "FORMERR",
[DNS_RCODE_BADTRUNC] = "BADTRUNC",
};
DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
+
+static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
+ [DNS_PROTOCOL_DNS] = "dns",
+ [DNS_PROTOCOL_MDNS] = "mdns",
+ [DNS_PROTOCOL_LLMNR] = "llmnr",
+};
+DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);