summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/resolved-dns-packet.c')
-rw-r--r--src/resolve/resolved-dns-packet.c369
1 files changed, 344 insertions, 25 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index bb74b1828e..b1cde4ab35 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -32,10 +32,10 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
assert(ret);
- if (mtu <= 0)
+ if (mtu <= UDP_PACKET_HEADER_SIZE)
a = DNS_PACKET_SIZE_START;
else
- a = mtu;
+ a = mtu - UDP_PACKET_HEADER_SIZE;
if (a < DNS_PACKET_HEADER_SIZE)
a = DNS_PACKET_HEADER_SIZE;
@@ -166,10 +166,17 @@ int dns_packet_validate_reply(DnsPacket *p) {
if (DNS_PACKET_OPCODE(p) != 0)
return -EBADMSG;
- /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
- if (p->protocol == DNS_PROTOCOL_LLMNR &&
- DNS_PACKET_QDCOUNT(p) != 1)
- return -EBADMSG;
+ switch (p->protocol) {
+ case DNS_PROTOCOL_LLMNR:
+ /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
+ if (DNS_PACKET_QDCOUNT(p) != 1)
+ return -EBADMSG;
+
+ break;
+
+ default:
+ break;
+ }
return 1;
}
@@ -192,18 +199,25 @@ int dns_packet_validate_query(DnsPacket *p) {
if (DNS_PACKET_TC(p))
return -EBADMSG;
- /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
- if (p->protocol == DNS_PROTOCOL_LLMNR &&
- DNS_PACKET_QDCOUNT(p) != 1)
- return -EBADMSG;
+ switch (p->protocol) {
+ case DNS_PROTOCOL_LLMNR:
+ /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
+ if (DNS_PACKET_QDCOUNT(p) != 1)
+ return -EBADMSG;
- /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
- if (DNS_PACKET_ANCOUNT(p) > 0)
- return -EBADMSG;
+ /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
+ if (DNS_PACKET_ANCOUNT(p) > 0)
+ return -EBADMSG;
- /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
- if (DNS_PACKET_NSCOUNT(p) > 0)
- return -EBADMSG;
+ /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
+ if (DNS_PACKET_NSCOUNT(p) > 0)
+ return -EBADMSG;
+
+ break;
+
+ default:
+ break;
+ }
return 1;
}
@@ -488,6 +502,90 @@ fail:
return r;
}
+static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) {
+ size_t saved_size;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ if (length == 0)
+ return 0;
+
+ saved_size = p->size;
+
+ r = dns_packet_append_uint8(p, window, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, length, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, types, length, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (start)
+ *start = saved_size;
+
+ return 0;
+fail:
+ dns_packet_truncate(p, saved_size);
+ return r;
+}
+
+static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
+ Iterator i;
+ uint8_t window = 0;
+ uint8_t len = 0;
+ uint8_t bitmaps[32] = {};
+ unsigned n;
+ size_t saved_size;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ saved_size = p->size;
+
+ BITMAP_FOREACH(n, types, i) {
+ uint8_t entry;
+
+ assert(n <= 0xffff);
+
+ if ((n << 8) != window) {
+ r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (len > 0) {
+ len = 0;
+ zero(bitmaps);
+ }
+ }
+
+ window = n << 8;
+ len ++;
+
+ entry = n & 255;
+
+ bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
+ }
+
+ r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (start)
+ *start = saved_size;
+
+ return 0;
+fail:
+ dns_packet_truncate(p, saved_size);
+ return r;
+}
+
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
size_t saved_size, rdlength_offset, end, rdlength;
int r;
@@ -638,6 +736,22 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
break;
+ case DNS_TYPE_DS:
+ r = dns_packet_append_uint16(p, rr->ds.key_tag, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->ds.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->ds.digest_type, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->ds.digest, rr->ds.digest_size, NULL);
+ break;
+
case DNS_TYPE_SSHFP:
r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
if (r < 0)
@@ -691,7 +805,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
if (r < 0)
goto fail;
- r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL);
+ r = dns_packet_append_uint16(p, rr->rrsig.key_tag, NULL);
if (r < 0)
goto fail;
@@ -702,6 +816,50 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
break;
+ case DNS_TYPE_NSEC:
+ r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_types(p, rr->nsec.types, NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
+ case DNS_TYPE_NSEC3:
+ r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_types(p, rr->nsec3.types, NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
case _DNS_TYPE_INVALID: /* unparseable */
default:
@@ -966,6 +1124,79 @@ fail:
return r;
}
+static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
+ uint8_t window;
+ uint8_t length;
+ const uint8_t *bitmap;
+ unsigned i;
+ bool found = false;
+ size_t saved_rindex;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ saved_rindex = p->rindex;
+
+ r = bitmap_ensure_allocated(types);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &window, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &length, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (length == 0 || length > 32)
+ return -EBADMSG;
+
+ r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
+ if (r < 0)
+ goto fail;
+
+ for (i = 0; i < length; i++) {
+ uint8_t bitmask = 1 << 7;
+ uint8_t bit = 0;
+
+ if (!bitmap[i]) {
+ found = false;
+ continue;
+ }
+
+ found = true;
+
+ while (bitmask) {
+ if (bitmap[i] & bitmask) {
+ uint16_t n;
+
+ /* XXX: ignore pseudo-types? see RFC4034 section 4.1.2 */
+ n = (uint16_t) window << 8 | (uint16_t) bit;
+
+ r = bitmap_set(*types, n);
+ if (r < 0)
+ goto fail;
+ }
+
+ bit ++;
+ bitmask >>= 1;
+ }
+ }
+
+ if (!found)
+ return -EBADMSG;
+
+ if (start)
+ *start = saved_rindex;
+
+ return 0;
+fail:
+ dns_packet_rewind(p, saved_rindex);
+ return r;
+}
+
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
_cleanup_free_ char *name = NULL;
uint16_t class, type;
@@ -1248,6 +1479,26 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
}
}
+ case DNS_TYPE_DS:
+ r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_public_key(p, rdlength - 4,
+ &rr->ds.digest, &rr->ds.digest_size,
+ NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
if (r < 0)
@@ -1332,6 +1583,72 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
NULL);
break;
+ case DNS_TYPE_NSEC:
+ r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL);
+ if (r < 0)
+ goto fail;
+
+ while (p->rindex != offset + rdlength) {
+ r = dns_packet_read_type_window(p, &rr->nsec.types, NULL);
+ if (r < 0)
+ goto fail;
+ }
+
+ break;
+
+ case DNS_TYPE_NSEC3: {
+ uint8_t size;
+
+ r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &size, NULL);
+ if (r < 0)
+ goto fail;
+
+ rr->nsec3.salt_size = size;
+
+ r = dns_packet_read_blob(p, &d, rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ rr->nsec3.salt = memdup(d, rr->nsec3.salt_size);
+ if (!rr->nsec3.salt) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ r = dns_packet_read_uint8(p, &size, NULL);
+ if (r < 0)
+ goto fail;
+
+ rr->nsec3.next_hashed_name_size = size;
+
+ r = dns_packet_read(p, rr->nsec3.next_hashed_name_size, &d, NULL);
+ if (r < 0)
+ goto fail;
+
+ rr->nsec3.next_hashed_name = memdup(d, rr->nsec3.next_hashed_name_size);
+ if (!rr->nsec3.next_hashed_name) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ r = dns_packet_append_types(p, rr->nsec3.types, NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
+ }
default:
unparseable:
r = dns_packet_read(p, rdlength, &d, NULL);
@@ -1466,13 +1783,15 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
- [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
- [DNSSEC_ALGORITHM_DH] = "DH",
- [DNSSEC_ALGORITHM_DSA] = "DSA",
- [DNSSEC_ALGORITHM_ECC] = "ECC",
- [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
- [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
- [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
- [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
+ [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
+ [DNSSEC_ALGORITHM_DH] = "DH",
+ [DNSSEC_ALGORITHM_DSA] = "DSA",
+ [DNSSEC_ALGORITHM_ECC] = "ECC",
+ [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
+ [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
+ [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
+ [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
+ [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
+ [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);