resolved-dns-packet.c revision a43a068a30f7a47aba39f8b48d5db0c4d39fd21d
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
8bdbb8d9cbe1d35708385573d70984ab4533812dLennart Poettering#include "alloc-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "dns-domain.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "resolved-dns-packet.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "string-table.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "strv.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "unaligned.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "utf8.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "util.h"
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#define EDNS0_OPT_DO (1<<15)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringint dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering DnsPacket *p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t a;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(ret);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (mtu <= UDP_PACKET_HEADER_SIZE)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = DNS_PACKET_SIZE_START;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen else
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen a = mtu - UDP_PACKET_HEADER_SIZE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (a < DNS_PACKET_HEADER_SIZE)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering a = DNS_PACKET_HEADER_SIZE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering /* round up to next page size */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* make sure we never allocate more than useful */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (a > DNS_PACKET_SIZE_MAX)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering a = DNS_PACKET_SIZE_MAX;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!p)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->allocated = a;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->protocol = protocol;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering p->opt_start = p->opt_size = (size_t) -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->n_ref = 1;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering *ret = p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsPacketHeader *h;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen h = DNS_PACKET_HEADER(p);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen switch(p->protocol) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen case DNS_PROTOCOL_LLMNR:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(!truncated);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* opcode */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* c */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* tc */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* t */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* ra */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* ad */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* cd */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* rcode */));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen case DNS_PROTOCOL_MDNS:
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* opcode */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* aa */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering truncated /* tc */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* rd (ask for recursion) */,
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen 0 /* ra */,
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen 0 /* ad */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* cd */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* rcode */));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering default:
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(!truncated);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* opcode */,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 0 /* aa */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* tc */,
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering 1 /* rd (ask for recursion) */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* ra */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 0 /* ad */,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen dnssec_checking_disabled /* cd */,
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering 0 /* rcode */));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen}
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu, bool dnssec_checking_disabled) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsPacket *p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(ret);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = dns_packet_new(&p, protocol, mtu);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Always set the TC bit to 0 initially.
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * If there are multiple packets later, we'll update the bit shortly before sending.
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering dns_packet_set_flags(p, dnssec_checking_disabled, false);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering *ret = p;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return 0;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart PoetteringDnsPacket *dns_packet_ref(DnsPacket *p) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!p)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(!p->on_stack);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(p->n_ref > 0);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering p->n_ref++;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return p;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen}
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic void dns_packet_free(DnsPacket *p) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen char *s;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(p);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering dns_question_unref(p->question);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering dns_answer_unref(p->answer);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering dns_resource_record_unref(p->opt);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering while ((s = hashmap_steal_first_key(p->names)))
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering free(s);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering hashmap_free(p->names);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering free(p->_data);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!p->on_stack)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering free(p);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart PoetteringDnsPacket *dns_packet_unref(DnsPacket *p) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!p)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(p->n_ref > 0);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering dns_packet_unref(p->more);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (p->n_ref == 1)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering dns_packet_free(p);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering else
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering p->n_ref--;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return NULL;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint dns_packet_validate(DnsPacket *p) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert(p);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (p->size < DNS_PACKET_HEADER_SIZE)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -EBADMSG;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (p->size > DNS_PACKET_SIZE_MAX)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -EBADMSG;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 1;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint dns_packet_validate_reply(DnsPacket *p) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering int r;
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert(p);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = dns_packet_validate(p);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering if (r < 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (DNS_PACKET_QR(p) != 1)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering if (DNS_PACKET_OPCODE(p) != 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -EBADMSG;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering switch (p->protocol) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering case DNS_PROTOCOL_LLMNR:
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (DNS_PACKET_QDCOUNT(p) != 1)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -EBADMSG;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering break;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering case DNS_PROTOCOL_MDNS:
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* RFC 6762, Section 18 */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (DNS_PACKET_RCODE(p) != 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -EBADMSG;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering break;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering default:
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering break;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 1;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint dns_packet_validate_query(DnsPacket *p) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering int r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert(p);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = dns_packet_validate(p);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (r < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_QR(p) != 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return 0;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_OPCODE(p) != 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_TC(p))
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering switch (p->protocol) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering case DNS_PROTOCOL_LLMNR:
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_QDCOUNT(p) != 1)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_ANCOUNT(p) > 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_NSCOUNT(p) > 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering break;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering case DNS_PROTOCOL_MDNS:
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* RFC 6762, Section 18 */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (DNS_PACKET_AA(p) != 0 ||
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_PACKET_RD(p) != 0 ||
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_PACKET_RA(p) != 0 ||
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_PACKET_AD(p) != 0 ||
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_PACKET_CD(p) != 0 ||
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering DNS_PACKET_RCODE(p) != 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -EBADMSG;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering break;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering default:
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 1;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (p->size + add > p->allocated) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t a;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen a = PAGE_ALIGN((p->size + add) * 2);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (a > DNS_PACKET_SIZE_MAX)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = DNS_PACKET_SIZE_MAX;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (p->size + add > a)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EMSGSIZE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (p->_data) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering void *d;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering d = realloc(p->_data, a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!d)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->_data = d;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->_data = malloc(a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!p->_data)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memzero((uint8_t*) p->_data + p->size, a - p->size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->allocated = a;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (start)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *start = p->size;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ret)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->size += add;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid dns_packet_truncate(DnsPacket *p, size_t sz) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Iterator i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char *s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering void *n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (p->size <= sz)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering HASHMAP_FOREACH_KEY(n, s, p->names, i) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (PTR_TO_SIZE(n) < sz)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering continue;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering hashmap_remove(p->names, s);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering free(s);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering p->size = sz;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringint dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering void *q;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(p);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = dns_packet_extend(p, l, &q, start);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering memcpy(q, d, l);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering void *d;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(p);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering ((uint8_t*) d)[0] = v;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringint dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering void *d;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek assert(p);
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering unaligned_write_be16(d, v);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
a6c616024db23fef34152c1432892824a07799ccLennart Poettering void *d;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(p);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering unaligned_write_be32(d, v);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
a6c616024db23fef34152c1432892824a07799ccLennart Poettering
a6c616024db23fef34152c1432892824a07799ccLennart Poetteringint dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(p);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dns_packet_append_raw_string(p, s, strlen(s), start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers void *d;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt assert(p);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt assert(s || size == 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (size > 255)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -E2BIG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_extend(p, 1 + size, &d, start);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers ((uint8_t*) d)[0] = (uint8_t) size;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (size > 0)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers memcpy(((uint8_t*) d) + 1, s, size);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_append_label(DnsPacket *p, const char *d, size_t l, bool canonical_candidate, size_t *start) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers uint8_t *w;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* Append a label to a packet. Optionally, does this in DNSSEC
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * canonical form, if this label is marked as a candidate for
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * it, and the canonical form logic is enabled for the
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * packet */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
27e72d6b22890ba4a8cbc05c49667cd1cccf1461Simon Peeters assert(p);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(d);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (l > DNS_LABEL_MAX)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return -E2BIG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_extend(p, 1 + l, (void**) &w, start);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers *(w++) = (uint8_t) l;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (p->canonical_form && canonical_candidate) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Generate in canonical form, as defined by DNSSEC
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * RFC 4034, Section 6.2, i.e. all lower-case. */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < l; i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering w[i] = (uint8_t) ascii_tolower(d[i]);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* Otherwise, just copy the string unaltered. This is
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * essential for DNS-SD, where the casing of labels
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * matters and needs to be retained. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memcpy(w, d, l);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
8c841f21f5042b11acc91cc1b039cb162cbbe8f4Djalal Harouni return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_append_name(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsPacket *p,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *name,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool allow_compression,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen bool canonical_candidate,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen size_t *start) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen size_t saved_size;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(p);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(name);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (p->refuse_compression)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen allow_compression = false;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen saved_size = p->size;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen while (!dns_name_is_root(name)) {
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering const char *z = name;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering char label[DNS_LABEL_MAX];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t n = 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (allow_compression)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers n = PTR_TO_SIZE(hashmap_get(p->names, name));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (n > 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(n < p->size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (n < 0x4000) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen goto fail;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto done;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_label_unescape(&name, label, sizeof(label));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_append_label(p, label, r, canonical_candidate, &n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen goto fail;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (allow_compression) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_free_ char *s = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen s = strdup(z);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!s) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = -ENOMEM;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen goto fail;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering s = NULL;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = dns_packet_append_uint8(p, 0, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering return r;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poetteringdone:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (start)
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering *start = saved_size;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poetteringfail:
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering dns_packet_truncate(p, saved_size);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering return r;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering}
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poetteringint dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering size_t saved_size;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering int r;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering assert(p);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering assert(k);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering saved_size = p->size;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (r < 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering goto fail;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = dns_packet_append_uint16(p, k->type, NULL);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (r < 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering goto fail;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering r = dns_packet_append_uint16(p, k->class, NULL);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (r < 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering goto fail;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (start)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering *start = saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringfail:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering dns_packet_truncate(p, saved_size);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringstatic int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, const uint8_t *types, size_t *start) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering size_t saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering int r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(types);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(length > 0);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering saved_size = p->size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint8(p, window, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint8(p, length, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_blob(p, types, length, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (start)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering *start = saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringfail:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering dns_packet_truncate(p, saved_size);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringstatic int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering Iterator i;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering uint8_t window = 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering uint8_t entry = 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering uint8_t bitmaps[32] = {};
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering unsigned n;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering size_t saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering int r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(p);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering saved_size = p->size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering BITMAP_FOREACH(n, types, i) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(n <= 0xffff);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if ((n >> 8) != window && bitmaps[entry / 8] != 0) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering zero(bitmaps);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering }
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering window = n >> 8;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering entry = n & 255;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering }
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (bitmaps[entry / 8] != 0) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering }
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (start)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering *start = saved_size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return 0;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringfail:
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering dns_packet_truncate(p, saved_size);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering}
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering/* Append the OPT pseudo-RR described in RFC6891 */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringint dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering size_t saved_size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering int r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(p);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* we must never advertise supported packet size smaller than the legacy max */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (p->opt_start != (size_t) -1)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return -EBUSY;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(p->opt_size == (size_t) -1);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering saved_size = p->size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* empty name */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint8(p, 0, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* type */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint16(p, DNS_TYPE_OPT, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* maximum udp packet that can be received */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint16(p, max_udp_size, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* extended RCODE and VERSION */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint16(p, 0, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* flags: DNSSEC OK (DO), see RFC3225 */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint16(p, edns0_do ? EDNS0_OPT_DO : 0, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* RDLENGTH */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (edns0_do) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* If DO is on, also append RFC6975 Algorithm data */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering static const uint8_t rfc6975[] = {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering 0, 5, /* OPTION_CODE: DAU */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering 0, 6, /* LIST_LENGTH */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering DNSSEC_ALGORITHM_RSASHA1,
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering DNSSEC_ALGORITHM_RSASHA256,
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering DNSSEC_ALGORITHM_RSASHA512,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNSSEC_ALGORITHM_ECDSAP256SHA256,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNSSEC_ALGORITHM_ECDSAP384SHA384,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering 0, 6, /* OPTION_CODE: DHU */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering 0, 3, /* LIST_LENGTH */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNSSEC_DIGEST_SHA1,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNSSEC_DIGEST_SHA256,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNSSEC_DIGEST_SHA384,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering 0, 7, /* OPTION_CODE: N3U */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering 0, 1, /* LIST_LENGTH */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering NSEC3_ALGORITHM_SHA1,
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering };
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, sizeof(rfc6975), NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering } else
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, 0, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNS_PACKET_HEADER(p)->arcount = htobe16(DNS_PACKET_ARCOUNT(p) + 1);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering p->opt_start = saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering p->opt_size = p->size - saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (start)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering *start = saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringfail:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering dns_packet_truncate(p, saved_size);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringint dns_packet_truncate_opt(DnsPacket *p) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (p->opt_start == (size_t) -1) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p->opt_size == (size_t) -1);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p->opt_size != (size_t) -1);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(DNS_PACKET_ARCOUNT(p) > 0);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (p->opt_start + p->opt_size != p->size)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return -EBUSY;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering dns_packet_truncate(p, p->opt_start);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DNS_PACKET_HEADER(p)->arcount = htobe16(DNS_PACKET_ARCOUNT(p) - 1);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering p->opt_start = p->opt_size = (size_t) -1;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 1;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringint dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering size_t saved_size, rdlength_offset, end, rdlength, rds;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering int r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(rr);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering saved_size = p->size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_key(p, rr->key, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->ttl, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Initially we write 0 here */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, 0, &rdlength_offset);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering rds = p->size - saved_size;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_SRV:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, rr->srv.port, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_name(p, rr->srv.name, true, false, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_PTR:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_NS:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_CNAME:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_DNAME:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_name(p, rr->ptr.name, true, false, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_HINFO:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_string(p, rr->hinfo.os, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_SPF: /* exactly the same as TXT */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_TXT:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (!rr->txt.items) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* RFC 6763, section 6.1 suggests to generate
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * single empty string for an empty array. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_raw_string(p, NULL, 0, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering } else {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering DnsTxtItem *i;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering LIST_FOREACH(items, i, rr->txt.items) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_raw_string(p, i->data, i->length, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_A:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_AAAA:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_SOA:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_name(p, rr->soa.mname, true, false, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_name(p, rr->soa.rname, true, false, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_MX:
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_append_name(p, rr->mx.exchange, true, false, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering case DNS_TYPE_LOC:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->loc.version, NULL);
3d94f76c99da13e5603831d0b278f8c8c21bcb02Lennart Poettering if (r < 0)
a4475f577bd0daf762d6c3b4e58bc484e0cb74afLennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->loc.size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek goto fail;
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek if (r < 0)
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
f69157a66ffe413b4cf8bd79057487fc8921e78bThomas Hindoe Paaboel Andersen r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering if (r < 0)
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case DNS_TYPE_DS:
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering r = dns_packet_append_uint16(p, rr->ds.key_tag, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->ds.algorithm, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->ds.digest_type, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_blob(p, rr->ds.digest, rr->ds.digest_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case DNS_TYPE_SSHFP:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
fbadf04511389c4a0687ba5e9baf0ecebdbb07f1Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering case DNS_TYPE_DNSKEY:
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = dns_packet_append_uint16(p, rr->dnskey.flags, NULL);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto fail;
fbadf04511389c4a0687ba5e9baf0ecebdbb07f1Lennart Poettering
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering r = dns_packet_append_uint8(p, rr->dnskey.protocol, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case DNS_TYPE_RRSIG:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL);
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
249968612f16a71df909d6e73785c18a9ff36a65Lennart Poettering r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = dns_packet_append_uint16(p, rr->rrsig.key_tag, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_name(p, rr->rrsig.signer, false, true, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt case DNS_TYPE_NSEC:
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, false, NULL);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering goto fail;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = dns_packet_append_types(p, rr->nsec.types, NULL);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering goto fail;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case DNS_TYPE_NSEC3:
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL);
3db729cb8e6822114e9323f4041dcdc080f2fb3cJason A. Donenfeld if (r < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt goto fail;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (r < 0)
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_types(p, rr->nsec3.types, NULL);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case DNS_TYPE_TLSA:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->tlsa.cert_usage, NULL);
a6c616024db23fef34152c1432892824a07799ccLennart Poettering if (r < 0)
a6c616024db23fef34152c1432892824a07799ccLennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->tlsa.selector, NULL);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = dns_packet_append_uint8(p, rr->tlsa.matching_type, NULL);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering goto fail;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt break;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering case DNS_TYPE_OPT:
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering case DNS_TYPE_OPENPGPKEY:
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt case _DNS_TYPE_INVALID: /* unparseable */
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt default:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = dns_packet_append_blob(p, rr->generic.data, rr->generic.data_size, NULL);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* Let's calculate the actual data size and update the field */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering rdlength = p->size - rdlength_offset - sizeof(uint16_t);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (rdlength > 0xFFFF) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = -ENOSPC;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering end = p->size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering p->size = rdlength_offset;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = dns_packet_append_uint16(p, rdlength, NULL);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (r < 0)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering goto fail;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering p->size = end;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (start)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering *start = saved_size;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (rdata_start)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering *rdata_start = rds;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringfail:
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering dns_packet_truncate(p, saved_size);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering}
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringint dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering assert(p);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (p->rindex + sz > p->size)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering return -EMSGSIZE;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ret)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (start)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *start = p->rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->rindex += sz;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringvoid dns_packet_rewind(DnsPacket *p, size_t idx) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(idx <= p->size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(idx >= DNS_PACKET_HEADER_SIZE);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p->rindex = idx;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const void *q;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(d);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering r = dns_packet_read(p, sz, &q, start);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return r;
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memcpy(d, q, sz);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int dns_packet_read_memdup(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsPacket *p, size_t size,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering void **ret, size_t *ret_size,
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek size_t *ret_start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const void *src;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t start;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(ret);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_read(p, size, &src, &start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (size <= 0)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering *ret = NULL;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering else {
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering void *copy;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering copy = memdup(src, size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!copy)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = copy;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ret_size)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret_size = size;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ret_start)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret_start = start;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const void *d;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen assert(p);
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen r = dns_packet_read(p, sizeof(uint8_t), &d, start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = ((uint8_t*) d)[0];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const void *d;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering r = dns_packet_read(p, sizeof(uint16_t), &d, start);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (r < 0)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return r;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering *ret = unaligned_read_be16(d);
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringint dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering const void *d;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering int r;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert(p);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = dns_packet_read(p, sizeof(uint32_t), &d, start);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = unaligned_read_be32(d);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t saved_rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const void *d;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering char *t;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint8_t c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering saved_rindex = p->rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_read_uint8(p, &c, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_read(p, c, &d, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (memchr(d, 0, c)) {
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering t = strndup(d, c);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (!t) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!utf8_is_valid(t)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering free(t);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *ret = t;
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (start)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *start = saved_rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringfail:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dns_packet_rewind(p, saved_rindex);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t saved_rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint8_t c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering saved_rindex = p->rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_read_uint8(p, &c, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dns_packet_read(p, c, ret, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (size)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *size = c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (start)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *start = saved_rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringfail:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dns_packet_rewind(p, saved_rindex);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint dns_packet_read_name(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering DnsPacket *p,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char **_ret,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool allow_compression,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t *start) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t saved_rindex, after_rindex = 0, jump_barrier;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_free_ char *ret = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t n = 0, allocated = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool first = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
249968612f16a71df909d6e73785c18a9ff36a65Lennart Poettering assert(p);
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering assert(_ret);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (p->refuse_compression)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering allow_compression = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering saved_rindex = p->rindex;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering jump_barrier = p->rindex;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (;;) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint8_t c, d;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = dns_packet_read_uint8(p, &c, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen goto fail;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (c == 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* End of name */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (c <= 63) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *label;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering /* Literal label */
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering r = dns_packet_read(p, c, (const void**) &label, NULL);
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
r = -ENOMEM;
goto fail;
}
if (first)
first = false;
else
ret[n++] = '.';
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
goto fail;
n += r;
continue;
} else if (allow_compression && (c & 0xc0) == 0xc0) {
uint16_t ptr;
/* Pointer */
r = dns_packet_read_uint8(p, &d, NULL);
if (r < 0)
goto fail;
ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
r = -EBADMSG;
goto fail;
}
if (after_rindex == 0)
after_rindex = p->rindex;
/* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
jump_barrier = ptr;
p->rindex = ptr;
} else {
r = -EBADMSG;
goto fail;
}
}
if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
r = -ENOMEM;
goto fail;
}
ret[n] = 0;
if (after_rindex != 0)
p->rindex= after_rindex;
*_ret = ret;
ret = NULL;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
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;
uint8_t bit = 0;
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;
if (!bitmap[i]) {
found = false;
bit += 8;
continue;
}
found = true;
while (bitmask) {
if (bitmap[i] & bitmask) {
uint16_t n;
n = (uint16_t) window << 8 | (uint16_t) bit;
/* Ignore pseudo-types. see RFC4034 section 4.1.2 */
if (dns_type_is_pseudo(n))
continue;
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;
}
static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
size_t saved_rindex;
int r;
saved_rindex = p->rindex;
while (p->rindex < saved_rindex + size) {
r = dns_packet_read_type_window(p, types, NULL);
if (r < 0)
goto fail;
/* don't read past end of current RR */
if (p->rindex > saved_rindex + size) {
r = -EBADMSG;
goto fail;
}
}
if (p->rindex != saved_rindex + size) {
r = -EBADMSG;
goto fail;
}
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, bool *ret_cache_flush, size_t *start) {
_cleanup_free_ char *name = NULL;
bool cache_flush = false;
uint16_t class, type;
DnsResourceKey *key;
size_t saved_rindex;
int r;
assert(p);
assert(ret);
saved_rindex = p->rindex;
r = dns_packet_read_name(p, &name, true, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint16(p, &type, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint16(p, &class, NULL);
if (r < 0)
goto fail;
if (p->protocol == DNS_PROTOCOL_MDNS) {
/* See RFC6762, Section 10.2 */
if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH)) {
class &= ~MDNS_RR_CACHE_FLUSH;
cache_flush = true;
}
}
key = dns_resource_key_new_consume(class, type, name);
if (!key) {
r = -ENOMEM;
goto fail;
}
name = NULL;
*ret = key;
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
return r;
}
static bool loc_size_ok(uint8_t size) {
uint8_t m = size >> 4, e = size & 0xF;
return m <= 9 && e <= 9 && (m > 0 || e == 0);
}
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
size_t saved_rindex, offset;
uint16_t rdlength;
bool cache_flush;
int r;
assert(p);
assert(ret);
saved_rindex = p->rindex;
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
goto fail;
if (!dns_class_is_valid_rr(key->class)||
!dns_type_is_valid_rr(key->type)) {
r = -EBADMSG;
goto fail;
}
rr = dns_resource_record_new(key);
if (!rr) {
r = -ENOMEM;
goto fail;
}
r = dns_packet_read_uint32(p, &rr->ttl, NULL);
if (r < 0)
goto fail;
/* RFC 2181, Section 8, suggests to
* treat a TTL with the MSB set as a zero TTL. */
if (rr->ttl & UINT32_C(0x80000000))
rr->ttl = 0;
r = dns_packet_read_uint16(p, &rdlength, NULL);
if (r < 0)
goto fail;
if (p->rindex + rdlength > p->size) {
r = -EBADMSG;
goto fail;
}
offset = p->rindex;
switch (rr->key->type) {
case DNS_TYPE_SRV:
r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
break;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
break;
case DNS_TYPE_HINFO:
r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
if (rdlength <= 0) {
DnsTxtItem *i;
/* RFC 6763, section 6.1 suggests to treat
* empty TXT RRs as equivalent to a TXT record
* with a single empty string. */
i = malloc0(offsetof(DnsTxtItem, data) + 1); /* for safety reasons we add an extra NUL byte */
if (!i)
return -ENOMEM;
rr->txt.items = i;
} else {
DnsTxtItem *last = NULL;
while (p->rindex < offset + rdlength) {
DnsTxtItem *i;
const void *data;
size_t sz;
r = dns_packet_read_raw_string(p, &data, &sz, NULL);
if (r < 0)
return r;
i = malloc0(offsetof(DnsTxtItem, data) + sz + 1); /* extra NUL byte at the end */
if (!i)
return -ENOMEM;
memcpy(i->data, data, sz);
i->length = sz;
LIST_INSERT_AFTER(items, rr->txt.items, last, i);
last = i;
}
}
r = 0;
break;
case DNS_TYPE_A:
r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
break;
case DNS_TYPE_AAAA:
r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
break;
case DNS_TYPE_SOA:
r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
break;
case DNS_TYPE_MX:
r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
break;
case DNS_TYPE_LOC: {
uint8_t t;
size_t pos;
r = dns_packet_read_uint8(p, &t, &pos);
if (r < 0)
goto fail;
if (t == 0) {
rr->loc.version = t;
r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
if (r < 0)
goto fail;
if (!loc_size_ok(rr->loc.size)) {
r = -EBADMSG;
goto fail;
}
r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
if (r < 0)
goto fail;
if (!loc_size_ok(rr->loc.horiz_pre)) {
r = -EBADMSG;
goto fail;
}
r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
if (r < 0)
goto fail;
if (!loc_size_ok(rr->loc.vert_pre)) {
r = -EBADMSG;
goto fail;
}
r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
if (r < 0)
goto fail;
break;
} else {
dns_packet_rewind(p, pos);
rr->unparseable = true;
goto unparseable;
}
}
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_memdup(p, rdlength - 4,
&rr->ds.digest, &rr->ds.digest_size,
NULL);
if (r < 0)
goto fail;
if (rr->ds.digest_size <= 0) {
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
r = -EBADMSG;
goto fail;
}
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_memdup(p, rdlength - 2,
&rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
NULL);
if (rr->sshfp.fingerprint_size <= 0) {
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
r = -EBADMSG;
goto fail;
}
break;
case DNS_TYPE_DNSKEY:
r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_memdup(p, rdlength - 4,
&rr->dnskey.key, &rr->dnskey.key_size,
NULL);
if (rr->dnskey.key_size <= 0) {
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
r = -EBADMSG;
goto fail;
}
break;
case DNS_TYPE_RRSIG:
r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
&rr->rrsig.signature, &rr->rrsig.signature_size,
NULL);
if (rr->rrsig.signature_size <= 0) {
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
r = -EBADMSG;
goto fail;
}
break;
case DNS_TYPE_NSEC: {
/*
* RFC6762, section 18.14 explictly states mDNS should use name compression.
* This contradicts RFC3845, section 2.1.1
*/
bool allow_compressed = p->protocol == DNS_PROTOCOL_MDNS;
r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
if (r < 0)
goto fail;
/* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself
* is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records
* without the NSEC bit set. */
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;
/* this may be zero */
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
goto fail;
if (size <= 0) {
r = -EBADMSG;
goto fail;
}
r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL);
if (r < 0)
goto fail;
/* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
break;
}
case DNS_TYPE_TLSA:
r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_memdup(p, rdlength - 3,
&rr->tlsa.data, &rr->tlsa.data_size,
NULL);
if (rr->tlsa.data_size <= 0) {
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
r = -EBADMSG;
goto fail;
}
break;
case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */
case DNS_TYPE_OPENPGPKEY:
default:
unparseable:
r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL);
if (r < 0)
goto fail;
break;
}
if (r < 0)
goto fail;
if (p->rindex != offset + rdlength) {
r = -EBADMSG;
goto fail;
}
*ret = rr;
rr = NULL;
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
return r;
}
static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
const uint8_t* p;
bool found_dau_dhu_n3u = false;
size_t l;
/* Checks whether the specified OPT RR is well-formed and whether it contains RFC6975 data (which is not OK in
* a reply). */
assert(rr);
assert(rr->key->type == DNS_TYPE_OPT);
/* Check that the version is 0 */
if (((rr->ttl >> 16) & UINT32_C(0xFF)) != 0)
return false;
p = rr->opt.data;
l = rr->opt.data_size;
while (l > 0) {
uint16_t option_code, option_length;
/* At least four bytes for OPTION-CODE and OPTION-LENGTH are required */
if (l < 4U)
return false;
option_code = unaligned_read_be16(p);
option_length = unaligned_read_be16(p + 2);
if (l < option_length + 4U)
return false;
/* RFC 6975 DAU, DHU or N3U fields found. */
if (IN_SET(option_code, 5, 6, 7))
found_dau_dhu_n3u = true;
p += option_length + 4U;
l -= option_length + 4U;
}
*rfc6975 = found_dau_dhu_n3u;
return true;
}
int dns_packet_extract(DnsPacket *p) {
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
size_t saved_rindex;
unsigned n, i;
int r;
if (p->extracted)
return 0;
saved_rindex = p->rindex;
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
n = DNS_PACKET_QDCOUNT(p);
if (n > 0) {
question = dns_question_new(n);
if (!question) {
r = -ENOMEM;
goto finish;
}
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
bool cache_flush;
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
goto finish;
if (cache_flush) {
r = -EBADMSG;
goto finish;
}
if (!dns_type_is_valid_query(key->type)) {
r = -EBADMSG;
goto finish;
}
r = dns_question_add(question, key);
if (r < 0)
goto finish;
}
}
n = DNS_PACKET_RRCOUNT(p);
if (n > 0) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *previous = NULL;
bool bad_opt = false;
answer = dns_answer_new(n);
if (!answer) {
r = -ENOMEM;
goto finish;
}
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
bool cache_flush;
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
if (r < 0)
goto finish;
/* Try to reduce memory usage a bit */
if (previous)
dns_resource_key_reduce(&rr->key, &previous->key);
if (rr->key->type == DNS_TYPE_OPT) {
bool has_rfc6975;
if (p->opt || bad_opt) {
/* Multiple OPT RRs? if so, let's ignore all, because there's something wrong
* with the server, and if one is valid we wouldn't know which one. */
log_debug("Multiple OPT RRs detected, ignoring all.");
bad_opt = true;
continue;
}
if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) {
/* If the OPT RR qis not owned by the root domain, then it is bad, let's ignore
* it. */
log_debug("OPT RR is not owned by root domain, ignoring.");
bad_opt = true;
continue;
}
if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) {
/* OPT RR is in the wrong section? Some Belkin routers do this. This is a hint
* the EDNS implementation is borked, like the Belkin one is, hence ignore
* it. */
log_debug("OPT RR in wrong section, ignoring.");
bad_opt = true;
continue;
}
if (!opt_is_good(rr, &has_rfc6975)) {
log_debug("Malformed OPT RR, ignoring.");
bad_opt = true;
continue;
}
if (has_rfc6975) {
/* If the OPT RR contains RFC6975 algorithm data, then this is indication that
* the server just copied the OPT it got from us (which contained that data)
* back into the reply. If so, then it doesn't properly support EDNS, as
* RFC6975 makes it very clear that the algorithm data should only be contained
* in questions, never in replies. Crappy Belkin routers copy the OPT data for
* example, hence let's detect this so that we downgrade early. */
log_debug("OPT RR contained RFC6975 data, ignoring.");
bad_opt = true;
continue;
}
p->opt = dns_resource_record_ref(rr);
} else {
/* According to RFC 4795, section 2.9. only the RRs from the Answer section shall be
* cached. Hence mark only those RRs as cacheable by default, but not the ones from the
* Additional or Authority sections. */
r = dns_answer_add(answer, rr, p->ifindex,
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0));
if (r < 0)
goto finish;
}
/* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note
* that we only do this if we actually decided to keep the RR around. */
dns_resource_record_unref(previous);
previous = dns_resource_record_ref(rr);
}
if (bad_opt)
p->opt = dns_resource_record_unref(p->opt);
}
p->question = question;
question = NULL;
p->answer = answer;
answer = NULL;
p->extracted = true;
r = 0;
finish:
p->rindex = saved_rindex;
return r;
}
int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
int r;
assert(p);
assert(key);
/* Checks if the specified packet is a reply for the specified
* key and the specified key is the only one in the question
* section. */
if (DNS_PACKET_QR(p) != 1)
return 0;
/* Let's unpack the packet, if that hasn't happened yet. */
r = dns_packet_extract(p);
if (r < 0)
return r;
if (p->question->n_keys != 1)
return 0;
return dns_resource_key_equal(p->question->keys[0], key);
}
static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
[DNS_RCODE_SUCCESS] = "SUCCESS",
[DNS_RCODE_FORMERR] = "FORMERR",
[DNS_RCODE_SERVFAIL] = "SERVFAIL",
[DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
[DNS_RCODE_NOTIMP] = "NOTIMP",
[DNS_RCODE_REFUSED] = "REFUSED",
[DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
[DNS_RCODE_YXRRSET] = "YRRSET",
[DNS_RCODE_NXRRSET] = "NXRRSET",
[DNS_RCODE_NOTAUTH] = "NOTAUTH",
[DNS_RCODE_NOTZONE] = "NOTZONE",
[DNS_RCODE_BADVERS] = "BADVERS",
[DNS_RCODE_BADKEY] = "BADKEY",
[DNS_RCODE_BADTIME] = "BADTIME",
[DNS_RCODE_BADMODE] = "BADMODE",
[DNS_RCODE_BADNAME] = "BADNAME",
[DNS_RCODE_BADALG] = "BADALG",
[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);