resolved-dns-packet.c revision 42cc2eebb01056beb7acd3ecfe8e533558237f84
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Lennart 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 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 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 Poetteringint dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* round up to next page size */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* make sure we never allocate more than useful */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering 0 /* opcode */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* rcode */));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0 /* opcode */,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering 0 /* rcode */));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic void dns_packet_free(DnsPacket *p) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering while ((s = hashmap_steal_first_key(p->names)))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart PoetteringDnsPacket *dns_packet_unref(DnsPacket *p) {
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_validate_query(DnsPacket *p) {
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
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 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringstatic void dns_packet_truncate(DnsPacket *p, size_t sz) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringint dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = dns_packet_extend(p, 1 + l, &d, start);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_extend(p, 1 + l, &w, start);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering n = PTR_TO_SIZE(hashmap_get(p->names, name));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (n < 0x4000) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_label_unescape(&name, label, sizeof(label));
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_label(p, label, r, &n);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_uint16(p, k->type, NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_packet_append_uint16(p, k->class, NULL);
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 r = dns_packet_append_key(p, rr->key, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_packet_append_uint32(p, rr->ttl, NULL);
goto fail;
case DNS_TYPE_SRV:
goto fail;
goto fail;
goto fail;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
case DNS_TYPE_HINFO:
goto fail;
case DNS_TYPE_TXT: {
goto fail;
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
case DNS_TYPE_SOA:
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
case DNS_TYPE_MX:
goto fail;
case DNS_TYPE_LOC:
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
case DNS_TYPE_SSHFP:
goto fail;
goto fail;
goto fail;
r = ENOSPC;
goto fail;
goto fail;
if (start)
fail:
assert(p);
return -EMSGSIZE;
if (ret)
if (start)
assert(p);
assert(p);
assert(d);
assert(p);
assert(p);
assert(p);
uint8_t c;
assert(p);
goto fail;
goto fail;
if (memchr(d, 0, c)) {
r = -EBADMSG;
goto fail;
t = strndup(d, c);
r = -ENOMEM;
goto fail;
if (!utf8_is_valid(t)) {
free(t);
r = -EBADMSG;
goto fail;
*ret = t;
if (start)
fail:
bool first = true;
assert(p);
uint8_t c, d;
goto fail;
const char *label;
goto fail;
goto fail;
r = -ENOMEM;
goto fail;
if (!first)
first = false;
goto fail;
r = -EBADMSG;
goto fail;
if (after_rindex == 0)
goto fail;
r = -ENOMEM;
goto fail;
ret[n] = 0;
if (after_rindex != 0)
if (start)
fail:
assert(p);
goto fail;
goto fail;
goto fail;
if (!key) {
r = -ENOMEM;
goto fail;
if (start)
fail:
assert(p);
goto fail;
r = -EBADMSG;
goto fail;
if (!rr) {
r = -ENOMEM;
goto fail;
goto fail;
goto fail;
r = -EBADMSG;
goto fail;
case DNS_TYPE_SRV:
goto fail;
goto fail;
goto fail;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
case DNS_TYPE_HINFO:
goto fail;
case DNS_TYPE_TXT: {
goto fail;
goto fail;
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
case DNS_TYPE_SOA:
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
case DNS_TYPE_MX:
goto fail;
case DNS_TYPE_LOC: {
uint8_t t;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
case DNS_TYPE_SSHFP:
goto fail;
goto fail;
goto fail;
r = -ENOMEM;
goto fail;
goto fail;
r = -ENOMEM;
goto fail;
goto fail;
r = -EBADMSG;
goto fail;
if (start)
fail:
n = DNS_PACKET_QDCOUNT(p);
if (!question) {
r = -ENOMEM;
goto finish;
goto finish;
goto finish;
n = DNS_PACKET_RRCOUNT(p);
if (!answer) {
r = -ENOMEM;
goto finish;
goto finish;
goto finish;