resolved-dns-rr.c revision f2af5ea3cbf54998ed41d2d21a3448abb92ca7ff
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering/***
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering This file is part of systemd.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Copyright 2014 Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is free software; you can redistribute it and/or modify it
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering under the terms of the GNU Lesser General Public License as published by
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering (at your option) any later version.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is distributed in the hope that it will be useful, but
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Lesser General Public License for more details.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering You should have received a copy of the GNU Lesser General Public License
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering***/
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering#include <math.h>
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering#include "alloc-util.h"
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek#include "dns-domain.h"
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek#include "dns-type.h"
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek#include "hexdecoct.h"
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering#include "resolved-dns-packet.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "resolved-dns-rr.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "string-table.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "string-util.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "strv.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering DnsResourceKey *k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering size_t l;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering l = strlen(name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k = malloc0(sizeof(DnsResourceKey) + l + 1);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!k)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->n_ref = 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->class = class;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->type = type;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering strcpy((char*) k + sizeof(DnsResourceKey), name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-SzmekDnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(key);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(cname);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (cname->key->type == DNS_TYPE_CNAME)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return dns_resource_key_new(key->class, key->type, cname->cname.name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering else {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering DnsResourceKey *k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering char *destination = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
39883f622f392d8579f4428fc5a789a102efbb10Lennart Poettering r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (r == 0)
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek return dns_resource_key_ref((DnsResourceKey*) key);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k = dns_resource_key_new_consume(key->class, key->type, destination);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!k) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(destination);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering DnsResourceKey *new_key;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering char *joined;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(ret);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(key);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (dns_name_is_root(name)) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering *ret = dns_resource_key_ref(key);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering new_key = dns_resource_key_new_consume(key->class, key->type, joined);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!new_key) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(joined);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return -ENOMEM;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering *ret = new_key;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering DnsResourceKey *k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k = new0(DnsResourceKey, 1);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!k)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->n_ref = 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->class = class;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->type = type;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->_name = name;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!k)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * set this to -1, they should not be reffed/unreffed */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(k->n_ref != (unsigned) -1);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(k->n_ref > 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->n_ref++;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return k;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!k)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(k->n_ref != (unsigned) -1);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(k->n_ref > 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (k->n_ref == 1) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(k->_name);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(k);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering } else
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering k->n_ref--;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringbool dns_resource_key_is_address(const DnsResourceKey *key) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(key);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Check if this is an A or AAAA resource key */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (a == b)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r <= 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (a->class != b->class)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (a->type != b->type)
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(key);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek assert(rr);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (key == rr->key)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Checks if an rr matches the specified key. If a search
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * domain is specified, it will also be checked if the key
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * with the search domain suffixed might match the RR. */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return 0;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return 0;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (r != 0)
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering return r;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (search_domain) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett _cleanup_free_ char *joined = NULL;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering if (r < 0)
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering return r;
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering }
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return 0;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett}
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächlerint dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) {
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler int r;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler assert(key);
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler assert(cname);
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov if (cname->class != key->class && key->class != DNS_CLASS_ANY)
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov return 0;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (cname->type == DNS_TYPE_CNAME)
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov else if (cname->type == DNS_TYPE_DNAME)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler else
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return 0;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (r != 0)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return r;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov if (search_domain) {
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov _cleanup_free_ char *joined = NULL;
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov if (r < 0)
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov return r;
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (cname->type == DNS_TYPE_CNAME)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname));
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett else if (cname->type == DNS_TYPE_DNAME)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname));
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett }
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return 0;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett}
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikulaint dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) {
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula assert(soa);
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula assert(key);
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula /* Checks whether 'soa' is a SOA record for the specified key. */
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (soa->class != key->class)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return 0;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (soa->type != DNS_TYPE_SOA)
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return 0;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering}
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringstatic void dns_resource_key_hash_func(const void *i, struct siphash *state) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering const DnsResourceKey *k = i;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering assert(k);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering siphash24_compress(&k->class, sizeof(k->class), state);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering siphash24_compress(&k->type, sizeof(k->type), state);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering}
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringstatic int dns_resource_key_compare_func(const void *a, const void *b) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering const DnsResourceKey *x = a, *y = b;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering int ret;
ef5bfcf668e6029faa78534dfeb2591df854cdefLennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (ret != 0)
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek return ret;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (x->type < y->type)
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return -1;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (x->type > y->type)
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return 1;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (x->class < y->class)
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return -1;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (x->class > y->class)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringconst struct hash_ops dns_resource_key_hash_ops = {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering .hash = dns_resource_key_hash_func,
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering .compare = dns_resource_key_compare_func
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering};
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering const char *c, *t, *n;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering char *s;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* If we cannot convert the CLASS/TYPE into a known string,
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering use the format recommended by RFC 3597, Section 5. */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering c = dns_class_to_string(key->class);
875c6e1b48f37a07dfbb80d6653c73f205e94260Lennart Poettering if (!c) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering sprintf(cbuf, "CLASS%u", key->class);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering c = cbuf;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek t = dns_type_to_string(key->type);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!t){
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering sprintf(tbuf, "TYPE%u", key->type);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek t = tbuf;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering }
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler n = DNS_RESOURCE_KEY_NAME(key);
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return -ENOMEM;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler *ret = s;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return 0;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler}
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
be3f52f4ed02a9256b1577719677b32a17b525acLennart PoetteringDnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering DnsResourceRecord *rr;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering rr = new0(DnsResourceRecord, 1);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering if (!rr)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return NULL;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering rr->n_ref = 1;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering rr->key = dns_resource_key_ref(key);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering rr->expiry = USEC_INFINITY;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return rr;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering}
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart PoetteringDnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering key = dns_resource_key_new(class, type, name);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering if (!key)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return NULL;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return dns_resource_record_new(key);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering}
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart PoetteringDnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (!rr)
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return NULL;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering assert(rr->n_ref > 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering rr->n_ref++;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return rr;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
73e231abde39f22097df50542c745e01de879836Jan Engelhardt
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!rr)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering assert(rr->n_ref > 0);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (rr->n_ref > 1) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering rr->n_ref--;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (rr->key) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering switch(rr->key->type) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek case DNS_TYPE_SRV:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->srv.name);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_PTR:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_NS:
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler case DNS_TYPE_CNAME:
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett case DNS_TYPE_DNAME:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->ptr.name);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek case DNS_TYPE_HINFO:
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek free(rr->hinfo.cpu);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->hinfo.os);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_TXT:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_SPF:
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering dns_txt_item_free_all(rr->txt.items);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering break;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering case DNS_TYPE_SOA:
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(rr->soa.mname);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->soa.rname);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek case DNS_TYPE_MX:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->mx.exchange);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_DS:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->ds.digest);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek break;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_SSHFP:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->sshfp.fingerprint);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering break;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering case DNS_TYPE_DNSKEY:
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering free(rr->dnskey.key);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek break;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
case DNS_TYPE_RRSIG:
free(rr->rrsig.signer);
free(rr->rrsig.signature);
break;
case DNS_TYPE_NSEC:
free(rr->nsec.next_domain_name);
bitmap_free(rr->nsec.types);
break;
case DNS_TYPE_NSEC3:
free(rr->nsec3.next_hashed_name);
free(rr->nsec3.salt);
bitmap_free(rr->nsec3.types);
break;
case DNS_TYPE_LOC:
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
break;
default:
free(rr->generic.data);
}
free(rr->wire_format);
dns_resource_key_unref(rr->key);
}
free(rr->to_string);
free(rr);
return NULL;
}
int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_free_ char *ptr = NULL;
int r;
assert(ret);
assert(address);
assert(hostname);
r = dns_name_reverse(family, address, &ptr);
if (r < 0)
return r;
key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
if (!key)
return -ENOMEM;
ptr = NULL;
rr = dns_resource_record_new(key);
if (!rr)
return -ENOMEM;
rr->ptr.name = strdup(hostname);
if (!rr->ptr.name)
return -ENOMEM;
*ret = rr;
rr = NULL;
return 0;
}
int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
DnsResourceRecord *rr;
assert(ret);
assert(address);
assert(family);
if (family == AF_INET) {
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
if (!rr)
return -ENOMEM;
rr->a.in_addr = address->in;
} else if (family == AF_INET6) {
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
if (!rr)
return -ENOMEM;
rr->aaaa.in6_addr = address->in6;
} else
return -EAFNOSUPPORT;
*ret = rr;
return 0;
}
int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
int r;
assert(a);
assert(b);
if (a == b)
return 1;
r = dns_resource_key_equal(a->key, b->key);
if (r <= 0)
return r;
if (a->unparseable != b->unparseable)
return 0;
switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
case DNS_TYPE_SRV:
r = dns_name_equal(a->srv.name, b->srv.name);
if (r <= 0)
return r;
return a->srv.priority == b->srv.priority &&
a->srv.weight == b->srv.weight &&
a->srv.port == b->srv.port;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
return dns_name_equal(a->ptr.name, b->ptr.name);
case DNS_TYPE_HINFO:
return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
strcaseeq(a->hinfo.os, b->hinfo.os);
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
return dns_txt_item_equal(a->txt.items, b->txt.items);
case DNS_TYPE_A:
return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
case DNS_TYPE_AAAA:
return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
case DNS_TYPE_SOA:
r = dns_name_equal(a->soa.mname, b->soa.mname);
if (r <= 0)
return r;
r = dns_name_equal(a->soa.rname, b->soa.rname);
if (r <= 0)
return r;
return a->soa.serial == b->soa.serial &&
a->soa.refresh == b->soa.refresh &&
a->soa.retry == b->soa.retry &&
a->soa.expire == b->soa.expire &&
a->soa.minimum == b->soa.minimum;
case DNS_TYPE_MX:
if (a->mx.priority != b->mx.priority)
return 0;
return dns_name_equal(a->mx.exchange, b->mx.exchange);
case DNS_TYPE_LOC:
assert(a->loc.version == b->loc.version);
return a->loc.size == b->loc.size &&
a->loc.horiz_pre == b->loc.horiz_pre &&
a->loc.vert_pre == b->loc.vert_pre &&
a->loc.latitude == b->loc.latitude &&
a->loc.longitude == b->loc.longitude &&
a->loc.altitude == b->loc.altitude;
case DNS_TYPE_DS:
return a->ds.key_tag == b->ds.key_tag &&
a->ds.algorithm == b->ds.algorithm &&
a->ds.digest_type == b->ds.digest_type &&
a->ds.digest_size == b->ds.digest_size &&
memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
case DNS_TYPE_SSHFP:
return a->sshfp.algorithm == b->sshfp.algorithm &&
a->sshfp.fptype == b->sshfp.fptype &&
a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
case DNS_TYPE_DNSKEY:
return a->dnskey.flags == b->dnskey.flags &&
a->dnskey.protocol == b->dnskey.protocol &&
a->dnskey.algorithm == b->dnskey.algorithm &&
a->dnskey.key_size == b->dnskey.key_size &&
memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
case DNS_TYPE_RRSIG:
/* do the fast comparisons first */
if (a->rrsig.type_covered != b->rrsig.type_covered ||
a->rrsig.algorithm != b->rrsig.algorithm ||
a->rrsig.labels != b->rrsig.labels ||
a->rrsig.original_ttl != b->rrsig.original_ttl ||
a->rrsig.expiration != b->rrsig.expiration ||
a->rrsig.inception != b->rrsig.inception ||
a->rrsig.key_tag != b->rrsig.key_tag ||
a->rrsig.signature_size != b->rrsig.signature_size ||
memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
return false;
return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
case DNS_TYPE_NSEC:
return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
bitmap_equal(a->nsec.types, b->nsec.types);
case DNS_TYPE_NSEC3:
return a->nsec3.algorithm == b->nsec3.algorithm &&
a->nsec3.flags == b->nsec3.flags &&
a->nsec3.iterations == b->nsec3.iterations &&
a->nsec3.salt_size == b->nsec3.salt_size &&
memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
bitmap_equal(a->nsec3.types, b->nsec3.types);
default:
return a->generic.size == b->generic.size &&
memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
}
}
static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
char *s;
char NS = latitude >= 1U<<31 ? 'N' : 'S';
char EW = longitude >= 1U<<31 ? 'E' : 'W';
int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
double siz = (size >> 4) * exp10((double) (size & 0xF));
double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
(lat / 60000 / 60),
(lat / 60000) % 60,
(lat % 60000) / 1000.,
NS,
(lon / 60000 / 60),
(lon / 60000) % 60,
(lon % 60000) / 1000.,
EW,
alt / 100.,
siz / 100.,
hor / 100.,
ver / 100.) < 0)
return NULL;
return s;
}
static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
struct tm tm;
assert(buf);
assert(l > strlen("YYYYMMDDHHmmSS"));
if (!gmtime_r(&sec, &tm))
return -EINVAL;
if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
return -EINVAL;
return 0;
}
static char *format_types(Bitmap *types) {
_cleanup_strv_free_ char **strv = NULL;
_cleanup_free_ char *str = NULL;
Iterator i;
unsigned type;
int r;
BITMAP_FOREACH(type, types, i) {
if (dns_type_to_string(type)) {
r = strv_extend(&strv, dns_type_to_string(type));
if (r < 0)
return NULL;
} else {
char *t;
r = asprintf(&t, "TYPE%u", type);
if (r < 0)
return NULL;
r = strv_consume(&strv, t);
if (r < 0)
return NULL;
}
}
str = strv_join(strv, " ");
if (!str)
return NULL;
return strjoin("( ", str, " )", NULL);
}
static char *format_txt(DnsTxtItem *first) {
DnsTxtItem *i;
size_t c = 1;
char *p, *s;
LIST_FOREACH(items, i, first)
c += i->length * 4 + 3;
p = s = new(char, c);
if (!s)
return NULL;
LIST_FOREACH(items, i, first) {
size_t j;
if (i != first)
*(p++) = ' ';
*(p++) = '"';
for (j = 0; j < i->length; j++) {
if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
*(p++) = '\\';
*(p++) = '0' + (i->data[j] / 100);
*(p++) = '0' + ((i->data[j] / 10) % 10);
*(p++) = '0' + (i->data[j] % 10);
} else
*(p++) = i->data[j];
}
*(p++) = '"';
}
*p = 0;
return s;
}
const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
_cleanup_free_ char *k = NULL, *t = NULL;
char *s;
int r;
assert(rr);
if (rr->to_string)
return rr->to_string;
r = dns_resource_key_to_string(rr->key, &k);
if (r < 0)
return NULL;
switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV:
r = asprintf(&s, "%s %u %u %u %s",
k,
rr->srv.priority,
rr->srv.weight,
rr->srv.port,
strna(rr->srv.name));
if (r < 0)
return NULL;
break;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
s = strjoin(k, " ", rr->ptr.name, NULL);
if (!s)
return NULL;
break;
case DNS_TYPE_HINFO:
s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
if (!s)
return NULL;
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
t = format_txt(rr->txt.items);
if (!t)
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return NULL;
break;
case DNS_TYPE_A: {
_cleanup_free_ char *x = NULL;
r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
if (r < 0)
return NULL;
s = strjoin(k, " ", x, NULL);
if (!s)
return NULL;
break;
}
case DNS_TYPE_AAAA:
r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
if (r < 0)
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return NULL;
break;
case DNS_TYPE_SOA:
r = asprintf(&s, "%s %s %s %u %u %u %u %u",
k,
strna(rr->soa.mname),
strna(rr->soa.rname),
rr->soa.serial,
rr->soa.refresh,
rr->soa.retry,
rr->soa.expire,
rr->soa.minimum);
if (r < 0)
return NULL;
break;
case DNS_TYPE_MX:
r = asprintf(&s, "%s %u %s",
k,
rr->mx.priority,
rr->mx.exchange);
if (r < 0)
return NULL;
break;
case DNS_TYPE_LOC:
assert(rr->loc.version == 0);
t = format_location(rr->loc.latitude,
rr->loc.longitude,
rr->loc.altitude,
rr->loc.size,
rr->loc.horiz_pre,
rr->loc.vert_pre);
if (!t)
return NULL;
s = strjoin(k, " ", t, NULL);
if (!s)
return NULL;
break;
case DNS_TYPE_DS:
t = hexmem(rr->ds.digest, rr->ds.digest_size);
if (!t)
return NULL;
r = asprintf(&s, "%s %u %u %u %s",
k,
rr->ds.key_tag,
rr->ds.algorithm,
rr->ds.digest_type,
t);
if (r < 0)
return NULL;
break;
case DNS_TYPE_SSHFP:
t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!t)
return NULL;
r = asprintf(&s, "%s %u %u %s",
k,
rr->sshfp.algorithm,
rr->sshfp.fptype,
t);
if (r < 0)
return NULL;
break;
case DNS_TYPE_DNSKEY: {
const char *alg;
alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
if (!t)
return NULL;
r = asprintf(&s, "%s %u %u %.*s%.*u %s",
k,
rr->dnskey.flags,
rr->dnskey.protocol,
alg ? -1 : 0, alg,
alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
t);
if (r < 0)
return NULL;
break;
}
case DNS_TYPE_RRSIG: {
const char *type, *alg;
char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
type = dns_type_to_string(rr->rrsig.type_covered);
alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
if (!t)
return NULL;
r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
if (r < 0)
return NULL;
r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
if (r < 0)
return NULL;
/* TYPE?? follows
* http://tools.ietf.org/html/rfc3597#section-5 */
r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
k,
type ?: "TYPE",
type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
alg ? -1 : 0, alg,
alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
rr->rrsig.labels,
rr->rrsig.original_ttl,
expiration,
inception,
rr->rrsig.key_tag,
rr->rrsig.signer,
t);
if (r < 0)
return NULL;
break;
}
case DNS_TYPE_NSEC:
t = format_types(rr->nsec.types);
if (!t)
return NULL;
r = asprintf(&s, "%s %s %s",
k,
rr->nsec.next_domain_name,
t);
if (r < 0)
return NULL;
break;
case DNS_TYPE_NSEC3: {
_cleanup_free_ char *salt = NULL, *hash = NULL;
if (rr->nsec3.salt_size > 0) {
salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
if (!salt)
return NULL;
}
hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
if (!hash)
return NULL;
t = format_types(rr->nsec3.types);
if (!t)
return NULL;
r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
k,
rr->nsec3.algorithm,
rr->nsec3.flags,
rr->nsec3.iterations,
rr->nsec3.salt_size > 0 ? salt : "-",
hash,
t);
if (r < 0)
return NULL;
break;
}
default:
t = hexmem(rr->generic.data, rr->generic.size);
if (!t)
return NULL;
/* Format as documented in RFC 3597, Section 5 */
r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
if (r < 0)
return NULL;
break;
}
rr->to_string = s;
return s;
}
int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
DnsPacket packet = {
.n_ref = 1,
.protocol = DNS_PROTOCOL_DNS,
.on_stack = true,
.refuse_compression = true,
.canonical_form = canonical,
};
size_t start, rds;
int r;
assert(rr);
/* Generates the RR in wire-format, optionally in the
* canonical form as discussed in the DNSSEC RFC 4034, Section
* 6.2. We allocate a throw-away DnsPacket object on the stack
* here, because we need some book-keeping for memory
* management, and can reuse the DnsPacket serializer, that
* can generate the canonical form, too, but also knows label
* compression and suchlike. */
if (rr->wire_format && rr->wire_format_canonical == canonical)
return 0;
r = dns_packet_append_rr(&packet, rr, &start, &rds);
if (r < 0)
return r;
assert(start == 0);
assert(packet._data);
free(rr->wire_format);
rr->wire_format = packet._data;
rr->wire_format_size = packet.size;
rr->wire_format_rdata_offset = rds;
rr->wire_format_canonical = canonical;
packet._data = NULL;
dns_packet_unref(&packet);
return 0;
}
DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
DnsTxtItem *n;
if (!i)
return NULL;
n = i->items_next;
free(i);
return dns_txt_item_free_all(n);
}
bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
if (a == b)
return true;
if (!a != !b)
return false;
if (!a)
return true;
if (a->length != b->length)
return false;
if (memcmp(a->data, b->data, a->length) != 0)
return false;
return dns_txt_item_equal(a->items_next, b->items_next);
}
static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
/* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
[DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
[DNSSEC_ALGORITHM_DH] = "DH",
[DNSSEC_ALGORITHM_DSA] = "DSA",
[DNSSEC_ALGORITHM_ECC] = "ECC",
[DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
[DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
[DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
[DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
[DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
[DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
[DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
[DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
[DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
[DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
[DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
/* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
[DNSSEC_DIGEST_SHA1] = "SHA-1",
[DNSSEC_DIGEST_SHA256] = "SHA-256",
[DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
[DNSSEC_DIGEST_SHA384] = "SHA-384",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int);