resolved-dns-packet.c revision 42cc2eebb01056beb7acd3ecfe8e533558237f84
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "utf8.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "strv.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-dns-domain.h"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "resolved-dns-packet.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsPacket *p;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(ret);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (mtu <= 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = DNS_PACKET_SIZE_START;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = mtu;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (a < DNS_PACKET_HEADER_SIZE)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = DNS_PACKET_HEADER_SIZE;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* round up to next page size */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* make sure we never allocate more than useful */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (a > DNS_PACKET_SIZE_MAX)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = DNS_PACKET_SIZE_MAX;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!p)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMEM;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->allocated = a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->protocol = protocol;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->n_ref = 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *ret = p;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsPacket *p;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsPacketHeader *h;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(ret);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_new(&p, protocol, mtu);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen h = DNS_PACKET_HEADER(p);
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (protocol == DNS_PROTOCOL_LLMNR)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering 0 /* opcode */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* c */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* tc */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* t */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* ra */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* ad */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* cd */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* rcode */));
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen else
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* opcode */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* aa */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* tc */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 1 /* rd (ask for recursion) */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* ra */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* ad */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* cd */,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering 0 /* rcode */));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *ret = p;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return 0;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart PoetteringDnsPacket *dns_packet_ref(DnsPacket *p) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!p)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return NULL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(p->n_ref > 0);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering p->n_ref++;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return p;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic void dns_packet_free(DnsPacket *p) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering char *s;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering dns_question_unref(p->question);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering dns_answer_unref(p->answer);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering while ((s = hashmap_steal_first_key(p->names)))
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering free(s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering hashmap_free(p->names);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering free(p->_data);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering free(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart PoetteringDnsPacket *dns_packet_unref(DnsPacket *p) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!p)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p->n_ref > 0);
c5ed93163e6ef51a7462aa558a7e0912b17c4951Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (p->n_ref == 1)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering dns_packet_free(p);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering else
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering p->n_ref--;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return NULL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringint dns_packet_validate(DnsPacket *p) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (p->size < DNS_PACKET_HEADER_SIZE)
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen return -EBADMSG;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen if (p->size > DNS_PACKET_SIZE_MAX)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersenint dns_packet_validate_reply(DnsPacket *p) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen assert(p);
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_validate(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen return r;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen if (DNS_PACKET_QR(p) != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen if (DNS_PACKET_OPCODE(p) != 0)
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (p->protocol == DNS_PROTOCOL_LLMNR &&
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DNS_PACKET_QDCOUNT(p) != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_validate_query(DnsPacket *p) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_validate(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen if (DNS_PACKET_QR(p) != 0)
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (DNS_PACKET_OPCODE(p) != 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (DNS_PACKET_TC(p))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (p->protocol == DNS_PROTOCOL_LLMNR &&
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering DNS_PACKET_QDCOUNT(p) != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (DNS_PACKET_ANCOUNT(p) > 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return -EBADMSG;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (DNS_PACKET_NSCOUNT(p) > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EBADMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return 1;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (p->size + add > p->allocated) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering size_t a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = PAGE_ALIGN((p->size + add) * 2);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (a > DNS_PACKET_SIZE_MAX)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering a = DNS_PACKET_SIZE_MAX;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (p->size + add > a)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EMSGSIZE;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (p->_data) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *d;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering d = realloc(p->_data, a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!d)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return -ENOMEM;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->_data = d;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->_data = malloc(a);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!p->_data)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -ENOMEM;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering memzero((uint8_t*) p->_data + p->size, a - p->size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering p->allocated = a;
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (start)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *start = p->size;
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (ret)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->size += add;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering}
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringstatic void dns_packet_truncate(DnsPacket *p, size_t sz) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering Iterator i;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering char *s;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering void *n;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering assert(p);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (p->size <= sz)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering HASHMAP_FOREACH_KEY(s, n, p->names, i) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (PTR_TO_SIZE(n) < sz)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering continue;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering hashmap_remove(p->names, s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering free(s);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->size = sz;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *q;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_extend(p, l, &q, start);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering memcpy(q, d, l);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringint dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *d;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((uint8_t*) d)[0] = v;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *d;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((uint8_t*) d)[1] = (uint8_t) v;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering void *d;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(p);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering ((uint8_t*) d)[0] = (uint8_t) (v >> 24);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering ((uint8_t*) d)[1] = (uint8_t) (v >> 16);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering ((uint8_t*) d)[2] = (uint8_t) (v >> 8);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering ((uint8_t*) d)[3] = (uint8_t) v;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering void *d;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t l;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(s);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering l = strlen(s);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (l > 255)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return -E2BIG;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = dns_packet_extend(p, 1 + l, &d, start);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return r;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering ((uint8_t*) d)[0] = (uint8_t) l;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering memcpy(((uint8_t*) d) + 1, s, l);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering void *w;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(d);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (l > DNS_LABEL_MAX)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return -E2BIG;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_extend(p, 1 + l, &w, start);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering ((uint8_t*) w)[0] = (uint8_t) l;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering memcpy(((uint8_t*) w) + 1, d, l);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering size_t saved_size;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering int r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(name);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering saved_size = p->size;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering while (*name) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering _cleanup_free_ char *s = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering char label[DNS_LABEL_MAX];
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering size_t n;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering n = PTR_TO_SIZE(hashmap_get(p->names, name));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (n > 0) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(n < p->size);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (n < 0x4000) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering goto fail;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering goto done;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering }
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering s = strdup(name);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (!s) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = -ENOMEM;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering goto fail;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_label_unescape(&name, label, sizeof(label));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering goto fail;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_label(p, label, r, &n);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering goto fail;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering goto fail;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering goto fail;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering s = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_append_uint8(p, 0, NULL);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringdone:
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (start)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering *start = saved_size;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringfail:
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering dns_packet_truncate(p, saved_size);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering size_t saved_size;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering int r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(p);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(k);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering saved_size = p->size;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering goto fail;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_uint16(p, k->type, NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering goto fail;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_uint16(p, k->class, NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto fail;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (start)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *start = saved_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringfail:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_packet_truncate(p, saved_size);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering size_t saved_size, rdlength_offset, end, rdlength;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering saved_size = p->size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_append_key(p, rr->key, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto fail;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_append_uint32(p, rr->ttl, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto fail;
/* Initially we write 0 here */
r = dns_packet_append_uint16(p, 0, &rdlength_offset);
if (r < 0)
goto fail;
switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV:
r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint16(p, rr->srv.port, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_name(p, rr->srv.name, NULL);
break;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
r = dns_packet_append_name(p, rr->ptr.name, NULL);
break;
case DNS_TYPE_HINFO:
r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_string(p, rr->hinfo.os, NULL);
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT: {
char **s;
STRV_FOREACH(s, rr->txt.strings) {
r = dns_packet_append_string(p, *s, NULL);
if (r < 0)
goto fail;
}
r = 0;
break;
}
case DNS_TYPE_A:
r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
break;
case DNS_TYPE_AAAA:
r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
break;
case DNS_TYPE_SOA:
r = dns_packet_append_name(p, rr->soa.mname, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_name(p, rr->soa.rname, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
break;
case DNS_TYPE_MX:
r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_name(p, rr->mx.exchange, NULL);
break;
case DNS_TYPE_LOC:
r = dns_packet_append_uint8(p, rr->loc.version, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint8(p, rr->loc.size, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint16(p, rr->loc.latitude, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint16(p, rr->loc.longitude, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint16(p, rr->loc.altitude, NULL);
break;
case DNS_TYPE_SSHFP:
r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
if (r < 0)
goto fail;
r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
break;
case _DNS_TYPE_INVALID: /* unparseable */
default:
r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
break;
}
if (r < 0)
goto fail;
/* Let's calculate the actual data size and update the field */
rdlength = p->size - rdlength_offset - sizeof(uint16_t);
if (rdlength > 0xFFFF) {
r = ENOSPC;
goto fail;
}
end = p->size;
p->size = rdlength_offset;
r = dns_packet_append_uint16(p, rdlength, NULL);
if (r < 0)
goto fail;
p->size = end;
if (start)
*start = saved_size;
return 0;
fail:
dns_packet_truncate(p, saved_size);
return r;
}
int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
assert(p);
if (p->rindex + sz > p->size)
return -EMSGSIZE;
if (ret)
*ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
if (start)
*start = p->rindex;
p->rindex += sz;
return 0;
}
void dns_packet_rewind(DnsPacket *p, size_t idx) {
assert(p);
assert(idx <= p->size);
assert(idx >= DNS_PACKET_HEADER_SIZE);
p->rindex = idx;
}
int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
const void *q;
int r;
assert(p);
assert(d);
r = dns_packet_read(p, sz, &q, start);
if (r < 0)
return r;
memcpy(d, q, sz);
return 0;
}
int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
const void *d;
int r;
assert(p);
r = dns_packet_read(p, sizeof(uint8_t), &d, start);
if (r < 0)
return r;
*ret = ((uint8_t*) d)[0];
return 0;
}
int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
const void *d;
int r;
assert(p);
r = dns_packet_read(p, sizeof(uint16_t), &d, start);
if (r < 0)
return r;
*ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
((uint16_t) ((uint8_t*) d)[1]);
return 0;
}
int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
const void *d;
int r;
assert(p);
r = dns_packet_read(p, sizeof(uint32_t), &d, start);
if (r < 0)
return r;
*ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
(((uint32_t) ((uint8_t*) d)[1]) << 16) |
(((uint32_t) ((uint8_t*) d)[2]) << 8) |
((uint32_t) ((uint8_t*) d)[3]);
return 0;
}
int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
size_t saved_rindex;
const void *d;
char *t;
uint8_t c;
int r;
assert(p);
saved_rindex = p->rindex;
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
goto fail;
r = dns_packet_read(p, c, &d, NULL);
if (r < 0)
goto fail;
if (memchr(d, 0, c)) {
r = -EBADMSG;
goto fail;
}
t = strndup(d, c);
if (!t) {
r = -ENOMEM;
goto fail;
}
if (!utf8_is_valid(t)) {
free(t);
r = -EBADMSG;
goto fail;
}
*ret = t;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
return r;
}
int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
size_t saved_rindex, after_rindex = 0;
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
int r;
assert(p);
assert(_ret);
saved_rindex = p->rindex;
for (;;) {
uint8_t c, d;
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
goto fail;
if (c == 0)
/* End of name */
break;
else if (c <= 63) {
_cleanup_free_ char *t = NULL;
const char *label;
/* Literal label */
r = dns_packet_read(p, c, (const void**) &label, NULL);
if (r < 0)
goto fail;
r = dns_label_escape(label, c, &t);
if (r < 0)
goto fail;
if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
r = -ENOMEM;
goto fail;
}
if (!first)
ret[n++] = '.';
else
first = false;
memcpy(ret + n, t, c);
n += r;
continue;
} else if ((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 >= saved_rindex) {
r = -EBADMSG;
goto fail;
}
if (after_rindex == 0)
after_rindex = p->rindex;
p->rindex = ptr;
} else
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;
}
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
_cleanup_free_ char *name = NULL;
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, 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;
key = dns_resource_key_new_consume(class, type, name);
if (!key) {
r = -ENOMEM;
goto fail;
}
name = NULL;
*ret = key;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
return r;
}
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, 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;
const void *d;
int r;
assert(p);
assert(ret);
saved_rindex = p->rindex;
r = dns_packet_read_key(p, &key, NULL);
if (r < 0)
goto fail;
if (key->class == DNS_CLASS_ANY ||
key->type == DNS_TYPE_ANY) {
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;
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, 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, 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: {
char *s;
while (p->rindex < offset + rdlength) {
r = dns_packet_read_string(p, &s, NULL);
if (r < 0)
goto fail;
r = strv_consume(&rr->txt.strings, s);
if (r < 0)
goto fail;
}
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, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_name(p, &rr->soa.rname, 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, 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;
r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
if (r < 0)
goto fail;
r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
if (r < 0)
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;
/* fall through */
}
}
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(p, rdlength - 2, &d, NULL);
if (r < 0)
goto fail;
rr->sshfp.key = memdup(d, rdlength - 2);
if (!rr->sshfp.key) {
r = -ENOMEM;
goto fail;
}
rr->sshfp.key_size = rdlength - 2;
break;
default:
r = dns_packet_read(p, rdlength, &d, NULL);
if (r < 0)
goto fail;
rr->generic.data = memdup(d, rdlength);
if (!rr->generic.data) {
r = -ENOMEM;
goto fail;
}
rr->generic.size = rdlength;
break;
}
if (r < 0)
goto fail;
if (p->rindex != offset + rdlength) {
r = -EBADMSG;
goto fail;
}
*ret = rr;
rr = NULL;
if (start)
*start = saved_rindex;
return 0;
fail:
dns_packet_rewind(p, saved_rindex);
return r;
}
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;
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;
r = dns_packet_read_key(p, &key, NULL);
if (r < 0)
goto finish;
r = dns_question_add(question, key);
if (r < 0)
goto finish;
}
}
n = DNS_PACKET_RRCOUNT(p);
if (n > 0) {
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;
r = dns_packet_read_rr(p, &rr, NULL);
if (r < 0)
goto finish;
r = dns_answer_add(answer, rr);
if (r < 0)
goto finish;
}
}
p->question = question;
question = NULL;
p->answer = answer;
answer = NULL;
r = 0;
finish:
p->rindex = saved_rindex;
return r;
}
static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
[DNS_RCODE_SUCCESS] = "SUCCESS",
[DNS_RCODE_FORMERR] = "FORMERR",
[DNS_RCODE_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);