X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fresolve%2Fresolved-dns-packet.c;h=5eaee2cb4f751e2be52a1475deb869366f3d6ad1;hb=ea917db9e662ae6e6d0ae07e0118b323688c8616;hp=e5a4a403411e332fd220737585de5642921ffd20;hpb=7e8e0422aeb16f2a09a40546c61df753d10029b6;p=elogind.git diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index e5a4a4034..5eaee2cb4 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -72,10 +72,26 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { h = DNS_PACKET_HEADER(p); - if (protocol == DNS_PROTOCOL_DNS) - h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0)); /* ask for recursion */ + if (protocol == DNS_PROTOCOL_LLMNR) + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, + 0 /* opcode */, + 0 /* c */, + 0 /* tc */, + 0 /* t */, + 0 /* ra */, + 0 /* ad */, + 0 /* cd */, + 0 /* rcode */)); else - h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0)); + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, + 0 /* opcode */, + 0 /* aa */, + 0 /* tc */, + 1 /* rd (ask for recursion) */, + 0 /* ra */, + 0 /* ad */, + 0 /* cd */, + 0 /* rcode */)); *ret = p; return 0; @@ -130,7 +146,7 @@ int dns_packet_validate(DnsPacket *p) { if (p->size > DNS_PACKET_SIZE_MAX) return -EBADMSG; - return 0; + return 1; } int dns_packet_validate_reply(DnsPacket *p) { @@ -142,13 +158,52 @@ int dns_packet_validate_reply(DnsPacket *p) { if (r < 0) return r; - if (DNS_PACKET_QR(p) == 0) + if (DNS_PACKET_QR(p) != 1) + return 0; + + 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; + return 1; +} + +int dns_packet_validate_query(DnsPacket *p) { + int r; + + assert(p); + + r = dns_packet_validate(p); + if (r < 0) + return r; + + if (DNS_PACKET_QR(p) != 0) + return 0; + if (DNS_PACKET_OPCODE(p) != 0) return -EBADMSG; - return 0; + 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; + + /* 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; + + return 1; } static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) { @@ -216,6 +271,20 @@ static void dns_packet_truncate(DnsPacket *p, size_t sz) { p->size = sz; } +int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) { + void *q; + int r; + + assert(p); + + r = dns_packet_extend(p, l, &q, start); + if (r < 0) + return r; + + memcpy(q, d, l); + return 0; +} + int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) { void *d; int r; @@ -242,7 +311,25 @@ int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) { return r; ((uint8_t*) d)[0] = (uint8_t) (v >> 8); - ((uint8_t*) d)[1] = (uint8_t) (v & 255); + ((uint8_t*) d)[1] = (uint8_t) v; + + return 0; +} + +int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) { + void *d; + int r; + + assert(p); + + r = dns_packet_extend(p, sizeof(uint32_t), &d, start); + if (r < 0) + return r; + + ((uint8_t*) d)[0] = (uint8_t) (v >> 24); + ((uint8_t*) d)[1] = (uint8_t) (v >> 16); + ((uint8_t*) d)[2] = (uint8_t) (v >> 8); + ((uint8_t*) d)[3] = (uint8_t) v; return 0; } @@ -387,6 +474,114 @@ fail: 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; + + assert(p); + assert(rr); + + saved_size = p->size; + + r = dns_packet_append_key(p, rr->key, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->ttl, NULL); + if (r < 0) + goto fail; + + /* Initially we write 0 here */ + r = dns_packet_append_uint16(p, 0, &rdlength_offset); + if (r < 0) + goto fail; + + switch (rr->key->type) { + + case DNS_TYPE_PTR: + case DNS_TYPE_NS: + case DNS_TYPE_CNAME: + r = dns_packet_append_name(p, rr->ptr.name, NULL); + break; + + case DNS_TYPE_HINFO: + r = dns_packet_append_string(p, rr->hinfo.cpu, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_string(p, rr->hinfo.os, NULL); + break; + + case DNS_TYPE_A: + r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL); + break; + + case DNS_TYPE_AAAA: + r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL); + break; + + case DNS_TYPE_SOA: + r = dns_packet_append_name(p, rr->soa.mname, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_name(p, rr->soa.rname, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->soa.serial, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->soa.refresh, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->soa.retry, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->soa.expire, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->soa.minimum, NULL); + break; + + case DNS_TYPE_MX: + case DNS_TYPE_TXT: + case DNS_TYPE_SRV: + case DNS_TYPE_DNAME: + case DNS_TYPE_SSHFP: + default: + r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL); + break; + } + if (r < 0) + goto fail; + + /* Let's calculate the actual data size and update the field */ + rdlength = p->size - rdlength_offset - sizeof(uint16_t); + if (rdlength > 0xFFFF) { + r = ENOSPC; + goto fail; + } + + end = p->size; + p->size = rdlength_offset; + r = dns_packet_append_uint16(p, rdlength, NULL); + if (r < 0) + goto fail; + p->size = end; + + return 0; + +fail: + dns_packet_truncate(p, saved_size); + return r; +} + + int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) { assert(p); @@ -411,6 +606,21 @@ void dns_packet_rewind(DnsPacket *p, size_t idx) { p->rindex = idx; } +int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) { + const void *q; + int r; + + assert(p); + assert(d); + + r = dns_packet_read(p, sz, &q, start); + if (r < 0) + return r; + + memcpy(d, q, sz); + return 0; +} + int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) { const void *d; int r; @@ -696,19 +906,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; case DNS_TYPE_A: - r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL); - if (r < 0) - goto fail; - - memcpy(&rr->a.in_addr, d, sizeof(struct in_addr)); + r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL); break; case DNS_TYPE_AAAA: - r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL); - if (r < 0) - goto fail; - - memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr)); + r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL); break; case DNS_TYPE_SOA: @@ -739,6 +941,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL); break; + case DNS_TYPE_MX: + case DNS_TYPE_TXT: + case DNS_TYPE_SRV: + case DNS_TYPE_DNAME: + case DNS_TYPE_SSHFP: default: r = dns_packet_read(p, rdlength, &d, NULL); if (r < 0)