LCOV - code coverage report
Current view: top level - resolve - resolved-dns-rr.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 599 1099 54.5 %
Date: 2019-08-22 15:41:25 Functions: 27 49 55.1 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <math.h>
       4             : 
       5             : #include "alloc-util.h"
       6             : #include "dns-domain.h"
       7             : #include "dns-type.h"
       8             : #include "escape.h"
       9             : #include "hexdecoct.h"
      10             : #include "memory-util.h"
      11             : #include "resolved-dns-dnssec.h"
      12             : #include "resolved-dns-packet.h"
      13             : #include "resolved-dns-rr.h"
      14             : #include "string-table.h"
      15             : #include "string-util.h"
      16             : #include "strv.h"
      17             : #include "terminal-util.h"
      18             : 
      19          18 : DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
      20             :         DnsResourceKey *k;
      21             :         size_t l;
      22             : 
      23          18 :         assert(name);
      24             : 
      25          18 :         l = strlen(name);
      26          18 :         k = malloc0(sizeof(DnsResourceKey) + l + 1);
      27          18 :         if (!k)
      28           0 :                 return NULL;
      29             : 
      30          18 :         k->n_ref = 1;
      31          18 :         k->class = class;
      32          18 :         k->type = type;
      33             : 
      34          18 :         strcpy((char*) k + sizeof(DnsResourceKey), name);
      35             : 
      36          18 :         return k;
      37             : }
      38             : 
      39           0 : DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
      40             :         int r;
      41             : 
      42           0 :         assert(key);
      43           0 :         assert(cname);
      44             : 
      45           0 :         assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
      46             : 
      47           0 :         if (cname->key->type == DNS_TYPE_CNAME)
      48           0 :                 return dns_resource_key_new(key->class, key->type, cname->cname.name);
      49             :         else {
      50             :                 DnsResourceKey *k;
      51           0 :                 char *destination = NULL;
      52             : 
      53           0 :                 r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
      54           0 :                 if (r < 0)
      55           0 :                         return NULL;
      56           0 :                 if (r == 0)
      57           0 :                         return dns_resource_key_ref((DnsResourceKey*) key);
      58             : 
      59           0 :                 k = dns_resource_key_new_consume(key->class, key->type, destination);
      60           0 :                 if (!k)
      61           0 :                         return mfree(destination);
      62             : 
      63           0 :                 return k;
      64             :         }
      65             : }
      66             : 
      67           0 : int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
      68             :         DnsResourceKey *new_key;
      69             :         char *joined;
      70             :         int r;
      71             : 
      72           0 :         assert(ret);
      73           0 :         assert(key);
      74           0 :         assert(name);
      75             : 
      76           0 :         if (dns_name_is_root(name)) {
      77           0 :                 *ret = dns_resource_key_ref(key);
      78           0 :                 return 0;
      79             :         }
      80             : 
      81           0 :         r = dns_name_concat(dns_resource_key_name(key), name, 0, &joined);
      82           0 :         if (r < 0)
      83           0 :                 return r;
      84             : 
      85           0 :         new_key = dns_resource_key_new_consume(key->class, key->type, joined);
      86           0 :         if (!new_key) {
      87           0 :                 free(joined);
      88           0 :                 return -ENOMEM;
      89             :         }
      90             : 
      91           0 :         *ret = new_key;
      92           0 :         return 0;
      93             : }
      94             : 
      95         476 : DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
      96             :         DnsResourceKey *k;
      97             : 
      98         476 :         assert(name);
      99             : 
     100         476 :         k = new0(DnsResourceKey, 1);
     101         476 :         if (!k)
     102           0 :                 return NULL;
     103             : 
     104         476 :         k->n_ref = 1;
     105         476 :         k->class = class;
     106         476 :         k->type = type;
     107         476 :         k->_name = name;
     108             : 
     109         476 :         return k;
     110             : }
     111             : 
     112         970 : DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
     113             : 
     114         970 :         if (!k)
     115           0 :                 return NULL;
     116             : 
     117             :         /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
     118             :          * set this to -1, they should not be reffed/unreffed */
     119         970 :         assert(k->n_ref != (unsigned) -1);
     120             : 
     121         970 :         assert(k->n_ref > 0);
     122         970 :         k->n_ref++;
     123             : 
     124         970 :         return k;
     125             : }
     126             : 
     127        1464 : DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
     128        1464 :         if (!k)
     129           0 :                 return NULL;
     130             : 
     131        1464 :         assert(k->n_ref != (unsigned) -1);
     132        1464 :         assert(k->n_ref > 0);
     133             : 
     134        1464 :         if (k->n_ref == 1) {
     135         494 :                 free(k->_name);
     136         494 :                 free(k);
     137             :         } else
     138         970 :                 k->n_ref--;
     139             : 
     140        1464 :         return NULL;
     141             : }
     142             : 
     143        1472 : const char* dns_resource_key_name(const DnsResourceKey *key) {
     144             :         const char *name;
     145             : 
     146        1472 :         if (!key)
     147           0 :                 return NULL;
     148             : 
     149        1472 :         if (key->_name)
     150        1428 :                 name = key->_name;
     151             :         else
     152          44 :                 name = (char*) key + sizeof(DnsResourceKey);
     153             : 
     154        1472 :         if (dns_name_is_root(name))
     155         204 :                 return ".";
     156             :         else
     157        1268 :                 return name;
     158             : }
     159             : 
     160           0 : bool dns_resource_key_is_address(const DnsResourceKey *key) {
     161           0 :         assert(key);
     162             : 
     163             :         /* Check if this is an A or AAAA resource key */
     164             : 
     165           0 :         return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA);
     166             : }
     167             : 
     168           0 : bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key) {
     169           0 :         assert(key);
     170             : 
     171             :         /* Check if this is a PTR resource key used in
     172             :            Service Instance Enumeration as described in RFC6763 p4.1. */
     173             : 
     174           0 :         if (key->type != DNS_TYPE_PTR)
     175           0 :                 return false;
     176             : 
     177           0 :         return dns_name_endswith(dns_resource_key_name(key), "_tcp.local") ||
     178           0 :                 dns_name_endswith(dns_resource_key_name(key), "_udp.local");
     179             : }
     180             : 
     181         480 : int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
     182             :         int r;
     183             : 
     184         480 :         if (a == b)
     185         480 :                 return 1;
     186             : 
     187           0 :         r = dns_name_equal(dns_resource_key_name(a), dns_resource_key_name(b));
     188           0 :         if (r <= 0)
     189           0 :                 return r;
     190             : 
     191           0 :         if (a->class != b->class)
     192           0 :                 return 0;
     193             : 
     194           0 :         if (a->type != b->type)
     195           0 :                 return 0;
     196             : 
     197           0 :         return 1;
     198             : }
     199             : 
     200           0 : int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) {
     201             :         int r;
     202             : 
     203           0 :         assert(key);
     204           0 :         assert(rr);
     205             : 
     206           0 :         if (key == rr->key)
     207           0 :                 return 1;
     208             : 
     209             :         /* Checks if an rr matches the specified key. If a search
     210             :          * domain is specified, it will also be checked if the key
     211             :          * with the search domain suffixed might match the RR. */
     212             : 
     213           0 :         if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
     214           0 :                 return 0;
     215             : 
     216           0 :         if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
     217           0 :                 return 0;
     218             : 
     219           0 :         r = dns_name_equal(dns_resource_key_name(rr->key), dns_resource_key_name(key));
     220           0 :         if (r != 0)
     221           0 :                 return r;
     222             : 
     223           0 :         if (search_domain) {
     224           0 :                 _cleanup_free_ char *joined = NULL;
     225             : 
     226           0 :                 r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
     227           0 :                 if (r < 0)
     228           0 :                         return r;
     229             : 
     230           0 :                 return dns_name_equal(dns_resource_key_name(rr->key), joined);
     231             :         }
     232             : 
     233           0 :         return 0;
     234             : }
     235             : 
     236           0 : int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) {
     237             :         int r;
     238             : 
     239           0 :         assert(key);
     240           0 :         assert(cname);
     241             : 
     242           0 :         if (cname->class != key->class && key->class != DNS_CLASS_ANY)
     243           0 :                 return 0;
     244             : 
     245           0 :         if (cname->type == DNS_TYPE_CNAME)
     246           0 :                 r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname));
     247           0 :         else if (cname->type == DNS_TYPE_DNAME)
     248           0 :                 r = dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(cname));
     249             :         else
     250           0 :                 return 0;
     251             : 
     252           0 :         if (r != 0)
     253           0 :                 return r;
     254             : 
     255           0 :         if (search_domain) {
     256           0 :                 _cleanup_free_ char *joined = NULL;
     257             : 
     258           0 :                 r = dns_name_concat(dns_resource_key_name(key), search_domain, 0, &joined);
     259           0 :                 if (r < 0)
     260           0 :                         return r;
     261             : 
     262           0 :                 if (cname->type == DNS_TYPE_CNAME)
     263           0 :                         return dns_name_equal(joined, dns_resource_key_name(cname));
     264           0 :                 else if (cname->type == DNS_TYPE_DNAME)
     265           0 :                         return dns_name_endswith(joined, dns_resource_key_name(cname));
     266             :         }
     267             : 
     268           0 :         return 0;
     269             : }
     270             : 
     271           0 : int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) {
     272           0 :         assert(soa);
     273           0 :         assert(key);
     274             : 
     275             :         /* Checks whether 'soa' is a SOA record for the specified key. */
     276             : 
     277           0 :         if (soa->class != key->class)
     278           0 :                 return 0;
     279             : 
     280           0 :         if (soa->type != DNS_TYPE_SOA)
     281           0 :                 return 0;
     282             : 
     283           0 :         return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa));
     284             : }
     285             : 
     286         476 : static void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash *state) {
     287         476 :         assert(k);
     288             : 
     289         476 :         dns_name_hash_func(dns_resource_key_name(k), state);
     290         476 :         siphash24_compress(&k->class, sizeof(k->class), state);
     291         476 :         siphash24_compress(&k->type, sizeof(k->type), state);
     292         476 : }
     293             : 
     294           0 : static int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y) {
     295             :         int ret;
     296             : 
     297           0 :         ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y));
     298           0 :         if (ret != 0)
     299           0 :                 return ret;
     300             : 
     301           0 :         ret = CMP(x->type, y->type);
     302           0 :         if (ret != 0)
     303           0 :                 return ret;
     304             : 
     305           0 :         ret = CMP(x->class, y->class);
     306           0 :         if (ret != 0)
     307           0 :                 return ret;
     308             : 
     309           0 :         return 0;
     310             : }
     311             : 
     312             : DEFINE_HASH_OPS(dns_resource_key_hash_ops, DnsResourceKey, dns_resource_key_hash_func, dns_resource_key_compare_func);
     313             : 
     314         732 : char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) {
     315             :         const char *c, *t;
     316         732 :         char *ans = buf;
     317             : 
     318             :         /* If we cannot convert the CLASS/TYPE into a known string,
     319             :            use the format recommended by RFC 3597, Section 5. */
     320             : 
     321         732 :         c = dns_class_to_string(key->class);
     322         732 :         t = dns_type_to_string(key->type);
     323             : 
     324         732 :         snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u",
     325             :                  dns_resource_key_name(key),
     326           0 :                  strempty(c), c ? "" : "CLASS", c ? 0 : key->class,
     327           0 :                  strempty(t), t ? "" : "TYPE", t ? 0 : key->type);
     328             : 
     329         732 :         return ans;
     330             : }
     331             : 
     332           0 : bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
     333           0 :         assert(a);
     334           0 :         assert(b);
     335             : 
     336             :         /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
     337             :          * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
     338             :          * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
     339             :          * superficial data. */
     340             : 
     341           0 :         if (!*a)
     342           0 :                 return false;
     343           0 :         if (!*b)
     344           0 :                 return false;
     345             : 
     346             :         /* We refuse merging const keys */
     347           0 :         if ((*a)->n_ref == (unsigned) -1)
     348           0 :                 return false;
     349           0 :         if ((*b)->n_ref == (unsigned) -1)
     350           0 :                 return false;
     351             : 
     352             :         /* Already the same? */
     353           0 :         if (*a == *b)
     354           0 :                 return true;
     355             : 
     356             :         /* Are they really identical? */
     357           0 :         if (dns_resource_key_equal(*a, *b) <= 0)
     358           0 :                 return false;
     359             : 
     360             :         /* Keep the one which already has more references. */
     361           0 :         if ((*a)->n_ref > (*b)->n_ref) {
     362           0 :                 dns_resource_key_unref(*b);
     363           0 :                 *b = dns_resource_key_ref(*a);
     364             :         } else {
     365           0 :                 dns_resource_key_unref(*a);
     366           0 :                 *a = dns_resource_key_ref(*b);
     367             :         }
     368             : 
     369           0 :         return true;
     370             : }
     371             : 
     372         970 : DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
     373             :         DnsResourceRecord *rr;
     374             : 
     375         970 :         rr = new0(DnsResourceRecord, 1);
     376         970 :         if (!rr)
     377           0 :                 return NULL;
     378             : 
     379         970 :         rr->n_ref = 1;
     380         970 :         rr->key = dns_resource_key_ref(key);
     381         970 :         rr->expiry = USEC_INFINITY;
     382         970 :         rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1;
     383             : 
     384         970 :         return rr;
     385             : }
     386             : 
     387          18 : DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
     388          18 :         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     389             : 
     390          18 :         key = dns_resource_key_new(class, type, name);
     391          18 :         if (!key)
     392           0 :                 return NULL;
     393             : 
     394          18 :         return dns_resource_record_new(key);
     395             : }
     396             : 
     397         970 : static DnsResourceRecord* dns_resource_record_free(DnsResourceRecord *rr) {
     398         970 :         assert(rr);
     399             : 
     400         970 :         if (rr->key) {
     401         970 :                 switch(rr->key->type) {
     402             : 
     403           0 :                 case DNS_TYPE_SRV:
     404           0 :                         free(rr->srv.name);
     405           0 :                         break;
     406             : 
     407         304 :                 case DNS_TYPE_PTR:
     408             :                 case DNS_TYPE_NS:
     409             :                 case DNS_TYPE_CNAME:
     410             :                 case DNS_TYPE_DNAME:
     411         304 :                         free(rr->ptr.name);
     412         304 :                         break;
     413             : 
     414           0 :                 case DNS_TYPE_HINFO:
     415           0 :                         free(rr->hinfo.cpu);
     416           0 :                         free(rr->hinfo.os);
     417           0 :                         break;
     418             : 
     419          72 :                 case DNS_TYPE_TXT:
     420             :                 case DNS_TYPE_SPF:
     421          72 :                         dns_txt_item_free_all(rr->txt.items);
     422          72 :                         break;
     423             : 
     424          56 :                 case DNS_TYPE_SOA:
     425          56 :                         free(rr->soa.mname);
     426          56 :                         free(rr->soa.rname);
     427          56 :                         break;
     428             : 
     429         114 :                 case DNS_TYPE_MX:
     430         114 :                         free(rr->mx.exchange);
     431         114 :                         break;
     432             : 
     433           4 :                 case DNS_TYPE_DS:
     434           4 :                         free(rr->ds.digest);
     435           4 :                         break;
     436             : 
     437          48 :                 case DNS_TYPE_SSHFP:
     438          48 :                         free(rr->sshfp.fingerprint);
     439          48 :                         break;
     440             : 
     441          69 :                 case DNS_TYPE_DNSKEY:
     442          69 :                         free(rr->dnskey.key);
     443          69 :                         break;
     444             : 
     445           4 :                 case DNS_TYPE_RRSIG:
     446           4 :                         free(rr->rrsig.signer);
     447           4 :                         free(rr->rrsig.signature);
     448           4 :                         break;
     449             : 
     450          49 :                 case DNS_TYPE_NSEC:
     451          49 :                         free(rr->nsec.next_domain_name);
     452          49 :                         bitmap_free(rr->nsec.types);
     453          49 :                         break;
     454             : 
     455           1 :                 case DNS_TYPE_NSEC3:
     456           1 :                         free(rr->nsec3.next_hashed_name);
     457           1 :                         free(rr->nsec3.salt);
     458           1 :                         bitmap_free(rr->nsec3.types);
     459           1 :                         break;
     460             : 
     461         193 :                 case DNS_TYPE_LOC:
     462             :                 case DNS_TYPE_A:
     463             :                 case DNS_TYPE_AAAA:
     464         193 :                         break;
     465             : 
     466           8 :                 case DNS_TYPE_TLSA:
     467           8 :                         free(rr->tlsa.data);
     468           8 :                         break;
     469             : 
     470          40 :                 case DNS_TYPE_CAA:
     471          40 :                         free(rr->caa.tag);
     472          40 :                         free(rr->caa.value);
     473          40 :                         break;
     474             : 
     475           8 :                 case DNS_TYPE_OPENPGPKEY:
     476             :                 default:
     477           8 :                         if (!rr->unparseable)
     478           8 :                                 free(rr->generic.data);
     479             :                 }
     480             : 
     481         970 :                 if (rr->unparseable)
     482           0 :                         free(rr->generic.data);
     483             : 
     484         970 :                 free(rr->wire_format);
     485         970 :                 dns_resource_key_unref(rr->key);
     486             :         }
     487             : 
     488         970 :         free(rr->to_string);
     489         970 :         return mfree(rr);
     490             : }
     491             : 
     492        2236 : DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsResourceRecord, dns_resource_record, dns_resource_record_free);
     493             : 
     494           0 : int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
     495           0 :         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     496           0 :         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
     497           0 :         _cleanup_free_ char *ptr = NULL;
     498             :         int r;
     499             : 
     500           0 :         assert(ret);
     501           0 :         assert(address);
     502           0 :         assert(hostname);
     503             : 
     504           0 :         r = dns_name_reverse(family, address, &ptr);
     505           0 :         if (r < 0)
     506           0 :                 return r;
     507             : 
     508           0 :         key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
     509           0 :         if (!key)
     510           0 :                 return -ENOMEM;
     511             : 
     512           0 :         ptr = NULL;
     513             : 
     514           0 :         rr = dns_resource_record_new(key);
     515           0 :         if (!rr)
     516           0 :                 return -ENOMEM;
     517             : 
     518           0 :         rr->ptr.name = strdup(hostname);
     519           0 :         if (!rr->ptr.name)
     520           0 :                 return -ENOMEM;
     521             : 
     522           0 :         *ret = TAKE_PTR(rr);
     523             : 
     524           0 :         return 0;
     525             : }
     526             : 
     527           0 : int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
     528             :         DnsResourceRecord *rr;
     529             : 
     530           0 :         assert(ret);
     531           0 :         assert(address);
     532           0 :         assert(family);
     533             : 
     534           0 :         if (family == AF_INET) {
     535             : 
     536           0 :                 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
     537           0 :                 if (!rr)
     538           0 :                         return -ENOMEM;
     539             : 
     540           0 :                 rr->a.in_addr = address->in;
     541             : 
     542           0 :         } else if (family == AF_INET6) {
     543             : 
     544           0 :                 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
     545           0 :                 if (!rr)
     546           0 :                         return -ENOMEM;
     547             : 
     548           0 :                 rr->aaaa.in6_addr = address->in6;
     549             :         } else
     550           0 :                 return -EAFNOSUPPORT;
     551             : 
     552           0 :         *ret = rr;
     553             : 
     554           0 :         return 0;
     555             : }
     556             : 
     557             : #define FIELD_EQUAL(a, b, field) \
     558             :         ((a).field ## _size == (b).field ## _size &&  \
     559             :          memcmp_safe((a).field, (b).field, (a).field ## _size) == 0)
     560             : 
     561         476 : int dns_resource_record_payload_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
     562             :         int r;
     563             : 
     564             :         /* Check if a and b are the same, but don't look at their keys */
     565             : 
     566         476 :         if (a->unparseable != b->unparseable)
     567           0 :                 return 0;
     568             : 
     569         476 :         switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
     570             : 
     571           0 :         case DNS_TYPE_SRV:
     572           0 :                 r = dns_name_equal(a->srv.name, b->srv.name);
     573           0 :                 if (r <= 0)
     574           0 :                         return r;
     575             : 
     576           0 :                 return a->srv.priority == b->srv.priority &&
     577           0 :                        a->srv.weight == b->srv.weight &&
     578           0 :                        a->srv.port == b->srv.port;
     579             : 
     580         152 :         case DNS_TYPE_PTR:
     581             :         case DNS_TYPE_NS:
     582             :         case DNS_TYPE_CNAME:
     583             :         case DNS_TYPE_DNAME:
     584         152 :                 return dns_name_equal(a->ptr.name, b->ptr.name);
     585             : 
     586           0 :         case DNS_TYPE_HINFO:
     587           0 :                 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
     588           0 :                        strcaseeq(a->hinfo.os, b->hinfo.os);
     589             : 
     590          36 :         case DNS_TYPE_SPF: /* exactly the same as TXT */
     591             :         case DNS_TYPE_TXT:
     592          36 :                 return dns_txt_item_equal(a->txt.items, b->txt.items);
     593             : 
     594          56 :         case DNS_TYPE_A:
     595          56 :                 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
     596             : 
     597          28 :         case DNS_TYPE_AAAA:
     598          28 :                 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
     599             : 
     600          28 :         case DNS_TYPE_SOA:
     601          28 :                 r = dns_name_equal(a->soa.mname, b->soa.mname);
     602          28 :                 if (r <= 0)
     603           0 :                         return r;
     604          28 :                 r = dns_name_equal(a->soa.rname, b->soa.rname);
     605          28 :                 if (r <= 0)
     606           0 :                         return r;
     607             : 
     608          56 :                 return a->soa.serial  == b->soa.serial &&
     609          28 :                        a->soa.refresh == b->soa.refresh &&
     610          28 :                        a->soa.retry   == b->soa.retry &&
     611          84 :                        a->soa.expire  == b->soa.expire &&
     612          28 :                        a->soa.minimum == b->soa.minimum;
     613             : 
     614          56 :         case DNS_TYPE_MX:
     615          56 :                 if (a->mx.priority != b->mx.priority)
     616           0 :                         return 0;
     617             : 
     618          56 :                 return dns_name_equal(a->mx.exchange, b->mx.exchange);
     619             : 
     620          12 :         case DNS_TYPE_LOC:
     621          12 :                 assert(a->loc.version == b->loc.version);
     622             : 
     623          24 :                 return a->loc.size == b->loc.size &&
     624          12 :                        a->loc.horiz_pre == b->loc.horiz_pre &&
     625          12 :                        a->loc.vert_pre == b->loc.vert_pre &&
     626          12 :                        a->loc.latitude == b->loc.latitude &&
     627          36 :                        a->loc.longitude == b->loc.longitude &&
     628          12 :                        a->loc.altitude == b->loc.altitude;
     629             : 
     630           0 :         case DNS_TYPE_DS:
     631           0 :                 return a->ds.key_tag == b->ds.key_tag &&
     632           0 :                        a->ds.algorithm == b->ds.algorithm &&
     633           0 :                        a->ds.digest_type == b->ds.digest_type &&
     634           0 :                        FIELD_EQUAL(a->ds, b->ds, digest);
     635             : 
     636          24 :         case DNS_TYPE_SSHFP:
     637          48 :                 return a->sshfp.algorithm == b->sshfp.algorithm &&
     638          48 :                        a->sshfp.fptype == b->sshfp.fptype &&
     639          24 :                        FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint);
     640             : 
     641          32 :         case DNS_TYPE_DNSKEY:
     642          64 :                 return a->dnskey.flags == b->dnskey.flags &&
     643          32 :                        a->dnskey.protocol == b->dnskey.protocol &&
     644          96 :                        a->dnskey.algorithm == b->dnskey.algorithm &&
     645          32 :                        FIELD_EQUAL(a->dnskey, b->dnskey, key);
     646             : 
     647           0 :         case DNS_TYPE_RRSIG:
     648             :                 /* do the fast comparisons first */
     649           0 :                 return a->rrsig.type_covered == b->rrsig.type_covered &&
     650           0 :                        a->rrsig.algorithm == b->rrsig.algorithm &&
     651           0 :                        a->rrsig.labels == b->rrsig.labels &&
     652           0 :                        a->rrsig.original_ttl == b->rrsig.original_ttl &&
     653           0 :                        a->rrsig.expiration == b->rrsig.expiration &&
     654           0 :                        a->rrsig.inception == b->rrsig.inception &&
     655           0 :                        a->rrsig.key_tag == b->rrsig.key_tag &&
     656           0 :                        FIELD_EQUAL(a->rrsig, b->rrsig, signature) &&
     657           0 :                        dns_name_equal(a->rrsig.signer, b->rrsig.signer);
     658             : 
     659          24 :         case DNS_TYPE_NSEC:
     660          48 :                 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
     661          24 :                        bitmap_equal(a->nsec.types, b->nsec.types);
     662             : 
     663           0 :         case DNS_TYPE_NSEC3:
     664           0 :                 return a->nsec3.algorithm == b->nsec3.algorithm &&
     665           0 :                        a->nsec3.flags == b->nsec3.flags &&
     666           0 :                        a->nsec3.iterations == b->nsec3.iterations &&
     667           0 :                        FIELD_EQUAL(a->nsec3, b->nsec3, salt) &&
     668           0 :                        FIELD_EQUAL(a->nsec3, b->nsec3, next_hashed_name) &&
     669           0 :                        bitmap_equal(a->nsec3.types, b->nsec3.types);
     670             : 
     671           4 :         case DNS_TYPE_TLSA:
     672           8 :                 return a->tlsa.cert_usage == b->tlsa.cert_usage &&
     673           4 :                        a->tlsa.selector == b->tlsa.selector &&
     674          12 :                        a->tlsa.matching_type == b->tlsa.matching_type &&
     675           4 :                        FIELD_EQUAL(a->tlsa, b->tlsa, data);
     676             : 
     677          20 :         case DNS_TYPE_CAA:
     678          40 :                 return a->caa.flags == b->caa.flags &&
     679          40 :                        streq(a->caa.tag, b->caa.tag) &&
     680          20 :                        FIELD_EQUAL(a->caa, b->caa, value);
     681             : 
     682           4 :         case DNS_TYPE_OPENPGPKEY:
     683             :         default:
     684           4 :                 return FIELD_EQUAL(a->generic, b->generic, data);
     685             :         }
     686             : }
     687             : 
     688         476 : int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
     689             :         int r;
     690             : 
     691         476 :         assert(a);
     692         476 :         assert(b);
     693             : 
     694         476 :         if (a == b)
     695           0 :                 return 1;
     696             : 
     697         476 :         r = dns_resource_key_equal(a->key, b->key);
     698         476 :         if (r <= 0)
     699           0 :                 return r;
     700             : 
     701         476 :         return dns_resource_record_payload_equal(a, b);
     702             : }
     703             : 
     704          18 : static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
     705             :                              uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
     706             :         char *s;
     707          18 :         char NS = latitude >= 1U<<31 ? 'N' : 'S';
     708          18 :         char EW = longitude >= 1U<<31 ? 'E' : 'W';
     709             : 
     710          18 :         int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
     711          18 :         int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
     712          18 :         double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
     713          18 :         double siz = (size >> 4) * exp10((double) (size & 0xF));
     714          18 :         double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
     715          18 :         double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
     716             : 
     717          18 :         if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
     718             :                      (lat / 60000 / 60),
     719          18 :                      (lat / 60000) % 60,
     720          18 :                      (lat % 60000) / 1000.,
     721             :                      NS,
     722             :                      (lon / 60000 / 60),
     723          18 :                      (lon / 60000) % 60,
     724          18 :                      (lon % 60000) / 1000.,
     725             :                      EW,
     726             :                      alt / 100.,
     727             :                      siz / 100.,
     728             :                      hor / 100.,
     729             :                      ver / 100.) < 0)
     730           0 :                 return NULL;
     731             : 
     732          18 :         return s;
     733             : }
     734             : 
     735           8 : static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
     736             :         struct tm tm;
     737             : 
     738           8 :         assert(buf);
     739           8 :         assert(l > STRLEN("YYYYMMDDHHmmSS"));
     740             : 
     741           8 :         if (!gmtime_r(&sec, &tm))
     742           0 :                 return -EINVAL;
     743             : 
     744           8 :         if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
     745           0 :                 return -EINVAL;
     746             : 
     747           8 :         return 0;
     748             : }
     749             : 
     750          38 : static char *format_types(Bitmap *types) {
     751          38 :         _cleanup_strv_free_ char **strv = NULL;
     752          38 :         _cleanup_free_ char *str = NULL;
     753             :         Iterator i;
     754             :         unsigned type;
     755             :         int r;
     756             : 
     757         257 :         BITMAP_FOREACH(type, types, i) {
     758         219 :                 if (dns_type_to_string(type)) {
     759         218 :                         r = strv_extend(&strv, dns_type_to_string(type));
     760         218 :                         if (r < 0)
     761           0 :                                 return NULL;
     762             :                 } else {
     763             :                         char *t;
     764             : 
     765           1 :                         r = asprintf(&t, "TYPE%u", type);
     766           1 :                         if (r < 0)
     767           0 :                                 return NULL;
     768             : 
     769           1 :                         r = strv_consume(&strv, t);
     770           1 :                         if (r < 0)
     771           0 :                                 return NULL;
     772             :                 }
     773             :         }
     774             : 
     775          38 :         str = strv_join(strv, " ");
     776          38 :         if (!str)
     777           0 :                 return NULL;
     778             : 
     779          38 :         return strjoin("( ", str, " )");
     780             : }
     781             : 
     782          54 : static char *format_txt(DnsTxtItem *first) {
     783             :         DnsTxtItem *i;
     784          54 :         size_t c = 1;
     785             :         char *p, *s;
     786             : 
     787         108 :         LIST_FOREACH(items, i, first)
     788          54 :                 c += i->length * 4 + 3;
     789             : 
     790          54 :         p = s = new(char, c);
     791          54 :         if (!s)
     792           0 :                 return NULL;
     793             : 
     794         108 :         LIST_FOREACH(items, i, first) {
     795             :                 size_t j;
     796             : 
     797          54 :                 if (i != first)
     798           0 :                         *(p++) = ' ';
     799             : 
     800          54 :                 *(p++) = '"';
     801             : 
     802        6612 :                 for (j = 0; j < i->length; j++) {
     803        6558 :                         if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
     804           0 :                                 *(p++) = '\\';
     805           0 :                                 *(p++) = '0' + (i->data[j] / 100);
     806           0 :                                 *(p++) = '0' + ((i->data[j] / 10) % 10);
     807           0 :                                 *(p++) = '0' + (i->data[j] % 10);
     808             :                         } else
     809        6558 :                                 *(p++) = i->data[j];
     810             :                 }
     811             : 
     812          54 :                 *(p++) = '"';
     813             :         }
     814             : 
     815          54 :         *p = 0;
     816          54 :         return s;
     817             : }
     818             : 
     819        1446 : const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
     820        1446 :         _cleanup_free_ char *t = NULL;
     821             :         char *s, k[DNS_RESOURCE_KEY_STRING_MAX];
     822             :         int r;
     823             : 
     824        1446 :         assert(rr);
     825             : 
     826        1446 :         if (rr->to_string)
     827         714 :                 return rr->to_string;
     828             : 
     829         732 :         dns_resource_key_to_string(rr->key, k, sizeof(k));
     830             : 
     831         732 :         switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
     832             : 
     833           0 :         case DNS_TYPE_SRV:
     834           0 :                 r = asprintf(&s, "%s %u %u %u %s",
     835             :                              k,
     836           0 :                              rr->srv.priority,
     837           0 :                              rr->srv.weight,
     838           0 :                              rr->srv.port,
     839           0 :                              strna(rr->srv.name));
     840           0 :                 if (r < 0)
     841           0 :                         return NULL;
     842           0 :                 break;
     843             : 
     844         228 :         case DNS_TYPE_PTR:
     845             :         case DNS_TYPE_NS:
     846             :         case DNS_TYPE_CNAME:
     847             :         case DNS_TYPE_DNAME:
     848         228 :                 s = strjoin(k, " ", rr->ptr.name);
     849         228 :                 if (!s)
     850           0 :                         return NULL;
     851             : 
     852         228 :                 break;
     853             : 
     854           0 :         case DNS_TYPE_HINFO:
     855           0 :                 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os);
     856           0 :                 if (!s)
     857           0 :                         return NULL;
     858           0 :                 break;
     859             : 
     860          54 :         case DNS_TYPE_SPF: /* exactly the same as TXT */
     861             :         case DNS_TYPE_TXT:
     862          54 :                 t = format_txt(rr->txt.items);
     863          54 :                 if (!t)
     864           0 :                         return NULL;
     865             : 
     866          54 :                 s = strjoin(k, " ", t);
     867          54 :                 if (!s)
     868           0 :                         return NULL;
     869          54 :                 break;
     870             : 
     871          85 :         case DNS_TYPE_A: {
     872          85 :                 _cleanup_free_ char *x = NULL;
     873             : 
     874          85 :                 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
     875          85 :                 if (r < 0)
     876           0 :                         return NULL;
     877             : 
     878          85 :                 s = strjoin(k, " ", x);
     879          85 :                 if (!s)
     880           0 :                         return NULL;
     881          85 :                 break;
     882             :         }
     883             : 
     884          42 :         case DNS_TYPE_AAAA:
     885          42 :                 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
     886          42 :                 if (r < 0)
     887           0 :                         return NULL;
     888             : 
     889          42 :                 s = strjoin(k, " ", t);
     890          42 :                 if (!s)
     891           0 :                         return NULL;
     892          42 :                 break;
     893             : 
     894          42 :         case DNS_TYPE_SOA:
     895          42 :                 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
     896             :                              k,
     897          42 :                              strna(rr->soa.mname),
     898          42 :                              strna(rr->soa.rname),
     899             :                              rr->soa.serial,
     900             :                              rr->soa.refresh,
     901             :                              rr->soa.retry,
     902             :                              rr->soa.expire,
     903             :                              rr->soa.minimum);
     904          42 :                 if (r < 0)
     905           0 :                         return NULL;
     906          42 :                 break;
     907             : 
     908          86 :         case DNS_TYPE_MX:
     909         172 :                 r = asprintf(&s, "%s %u %s",
     910             :                              k,
     911          86 :                              rr->mx.priority,
     912             :                              rr->mx.exchange);
     913          86 :                 if (r < 0)
     914           0 :                         return NULL;
     915          86 :                 break;
     916             : 
     917          18 :         case DNS_TYPE_LOC:
     918          18 :                 assert(rr->loc.version == 0);
     919             : 
     920          72 :                 t = format_location(rr->loc.latitude,
     921             :                                     rr->loc.longitude,
     922             :                                     rr->loc.altitude,
     923          18 :                                     rr->loc.size,
     924          18 :                                     rr->loc.horiz_pre,
     925          18 :                                     rr->loc.vert_pre);
     926          18 :                 if (!t)
     927           0 :                         return NULL;
     928             : 
     929          18 :                 s = strjoin(k, " ", t);
     930          18 :                 if (!s)
     931           0 :                         return NULL;
     932          18 :                 break;
     933             : 
     934           4 :         case DNS_TYPE_DS:
     935           4 :                 t = hexmem(rr->ds.digest, rr->ds.digest_size);
     936           4 :                 if (!t)
     937           0 :                         return NULL;
     938             : 
     939          16 :                 r = asprintf(&s, "%s %u %u %u %s",
     940             :                              k,
     941           4 :                              rr->ds.key_tag,
     942           4 :                              rr->ds.algorithm,
     943           4 :                              rr->ds.digest_type,
     944             :                              t);
     945           4 :                 if (r < 0)
     946           0 :                         return NULL;
     947           4 :                 break;
     948             : 
     949          36 :         case DNS_TYPE_SSHFP:
     950          36 :                 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
     951          36 :                 if (!t)
     952           0 :                         return NULL;
     953             : 
     954         108 :                 r = asprintf(&s, "%s %u %u %s",
     955             :                              k,
     956          36 :                              rr->sshfp.algorithm,
     957          36 :                              rr->sshfp.fptype,
     958             :                              t);
     959          36 :                 if (r < 0)
     960           0 :                         return NULL;
     961          36 :                 break;
     962             : 
     963          53 :         case DNS_TYPE_DNSKEY: {
     964          53 :                 _cleanup_free_ char *alg = NULL;
     965             :                 char *ss;
     966             :                 uint16_t key_tag;
     967             : 
     968          53 :                 key_tag = dnssec_keytag(rr, true);
     969             : 
     970          53 :                 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
     971          53 :                 if (r < 0)
     972           0 :                         return NULL;
     973             : 
     974         159 :                 r = asprintf(&s, "%s %u %u %s",
     975             :                              k,
     976          53 :                              rr->dnskey.flags,
     977          53 :                              rr->dnskey.protocol,
     978             :                              alg);
     979          53 :                 if (r < 0)
     980           0 :                         return NULL;
     981             : 
     982         106 :                 r = base64_append(&s, r,
     983          53 :                                   rr->dnskey.key, rr->dnskey.key_size,
     984          53 :                                   8, columns());
     985          53 :                 if (r < 0)
     986           0 :                         return NULL;
     987             : 
     988         159 :                 r = asprintf(&ss, "%s\n"
     989             :                              "        -- Flags:%s%s%s\n"
     990             :                              "        -- Key tag: %u",
     991             :                              s,
     992          53 :                              rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
     993          53 :                              rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
     994          53 :                              rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
     995             :                              key_tag);
     996          53 :                 if (r < 0)
     997           0 :                         return NULL;
     998          53 :                 free(s);
     999          53 :                 s = ss;
    1000             : 
    1001          53 :                 break;
    1002             :         }
    1003             : 
    1004           4 :         case DNS_TYPE_RRSIG: {
    1005           4 :                 _cleanup_free_ char *alg = NULL;
    1006             :                 char expiration[STRLEN("YYYYMMDDHHmmSS") + 1], inception[STRLEN("YYYYMMDDHHmmSS") + 1];
    1007             :                 const char *type;
    1008             : 
    1009           4 :                 type = dns_type_to_string(rr->rrsig.type_covered);
    1010             : 
    1011           4 :                 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
    1012           4 :                 if (r < 0)
    1013           0 :                         return NULL;
    1014             : 
    1015           4 :                 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
    1016           4 :                 if (r < 0)
    1017           0 :                         return NULL;
    1018             : 
    1019           4 :                 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
    1020           4 :                 if (r < 0)
    1021           0 :                         return NULL;
    1022             : 
    1023             :                 /* TYPE?? follows
    1024             :                  * http://tools.ietf.org/html/rfc3597#section-5 */
    1025             : 
    1026           8 :                 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s",
    1027             :                              k,
    1028           4 :                              type ?: "TYPE",
    1029           0 :                              type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
    1030             :                              alg,
    1031           4 :                              rr->rrsig.labels,
    1032             :                              rr->rrsig.original_ttl,
    1033             :                              expiration,
    1034             :                              inception,
    1035           4 :                              rr->rrsig.key_tag,
    1036             :                              rr->rrsig.signer);
    1037           4 :                 if (r < 0)
    1038           0 :                         return NULL;
    1039             : 
    1040           8 :                 r = base64_append(&s, r,
    1041           4 :                                   rr->rrsig.signature, rr->rrsig.signature_size,
    1042           4 :                                   8, columns());
    1043           4 :                 if (r < 0)
    1044           0 :                         return NULL;
    1045             : 
    1046           4 :                 break;
    1047             :         }
    1048             : 
    1049          37 :         case DNS_TYPE_NSEC:
    1050          37 :                 t = format_types(rr->nsec.types);
    1051          37 :                 if (!t)
    1052           0 :                         return NULL;
    1053             : 
    1054          37 :                 r = asprintf(&s, "%s %s %s",
    1055             :                              k,
    1056             :                              rr->nsec.next_domain_name,
    1057             :                              t);
    1058          37 :                 if (r < 0)
    1059           0 :                         return NULL;
    1060          37 :                 break;
    1061             : 
    1062           1 :         case DNS_TYPE_NSEC3: {
    1063           2 :                 _cleanup_free_ char *salt = NULL, *hash = NULL;
    1064             : 
    1065           1 :                 if (rr->nsec3.salt_size > 0) {
    1066           1 :                         salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
    1067           1 :                         if (!salt)
    1068           0 :                                 return NULL;
    1069             :                 }
    1070             : 
    1071           1 :                 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
    1072           1 :                 if (!hash)
    1073           0 :                         return NULL;
    1074             : 
    1075           1 :                 t = format_types(rr->nsec3.types);
    1076           1 :                 if (!t)
    1077           0 :                         return NULL;
    1078             : 
    1079           1 :                 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
    1080             :                              k,
    1081           1 :                              rr->nsec3.algorithm,
    1082           1 :                              rr->nsec3.flags,
    1083           1 :                              rr->nsec3.iterations,
    1084           1 :                              rr->nsec3.salt_size > 0 ? salt : "-",
    1085             :                              hash,
    1086             :                              t);
    1087           1 :                 if (r < 0)
    1088           0 :                         return NULL;
    1089             : 
    1090           1 :                 break;
    1091             :         }
    1092             : 
    1093           6 :         case DNS_TYPE_TLSA: {
    1094             :                 const char *cert_usage, *selector, *matching_type;
    1095             : 
    1096           6 :                 cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
    1097           6 :                 selector = tlsa_selector_to_string(rr->tlsa.selector);
    1098           6 :                 matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
    1099             : 
    1100           6 :                 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
    1101           6 :                 if (!t)
    1102           0 :                         return NULL;
    1103             : 
    1104          24 :                 r = asprintf(&s,
    1105             :                              "%s %u %u %u %s\n"
    1106             :                              "        -- Cert. usage: %s\n"
    1107             :                              "        -- Selector: %s\n"
    1108             :                              "        -- Matching type: %s",
    1109             :                              k,
    1110           6 :                              rr->tlsa.cert_usage,
    1111           6 :                              rr->tlsa.selector,
    1112           6 :                              rr->tlsa.matching_type,
    1113             :                              t,
    1114             :                              cert_usage,
    1115             :                              selector,
    1116             :                              matching_type);
    1117           6 :                 if (r < 0)
    1118           0 :                         return NULL;
    1119             : 
    1120           6 :                 break;
    1121             :         }
    1122             : 
    1123          30 :         case DNS_TYPE_CAA: {
    1124          30 :                 _cleanup_free_ char *value;
    1125             : 
    1126          30 :                 value = octescape(rr->caa.value, rr->caa.value_size);
    1127          30 :                 if (!value)
    1128           0 :                         return NULL;
    1129             : 
    1130          90 :                 r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u",
    1131             :                              k,
    1132          30 :                              rr->caa.flags,
    1133             :                              rr->caa.tag,
    1134             :                              value,
    1135          30 :                              rr->caa.flags ? "\n        -- Flags:" : "",
    1136          30 :                              rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "",
    1137          30 :                              rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "",
    1138          30 :                              rr->caa.flags & ~CAA_FLAG_CRITICAL);
    1139          30 :                 if (r < 0)
    1140           0 :                         return NULL;
    1141             : 
    1142          30 :                 break;
    1143             :         }
    1144             : 
    1145           6 :         case DNS_TYPE_OPENPGPKEY: {
    1146           6 :                 r = asprintf(&s, "%s", k);
    1147           6 :                 if (r < 0)
    1148           0 :                         return NULL;
    1149             : 
    1150          12 :                 r = base64_append(&s, r,
    1151           6 :                                   rr->generic.data, rr->generic.data_size,
    1152           6 :                                   8, columns());
    1153           6 :                 if (r < 0)
    1154           0 :                         return NULL;
    1155           6 :                 break;
    1156             :         }
    1157             : 
    1158           0 :         default:
    1159           0 :                 t = hexmem(rr->generic.data, rr->generic.data_size);
    1160           0 :                 if (!t)
    1161           0 :                         return NULL;
    1162             : 
    1163             :                 /* Format as documented in RFC 3597, Section 5 */
    1164           0 :                 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t);
    1165           0 :                 if (r < 0)
    1166           0 :                         return NULL;
    1167           0 :                 break;
    1168             :         }
    1169             : 
    1170         732 :         rr->to_string = s;
    1171         732 :         return s;
    1172             : }
    1173             : 
    1174           0 : ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
    1175           0 :         assert(rr);
    1176           0 :         assert(out);
    1177             : 
    1178           0 :         switch(rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
    1179           0 :         case DNS_TYPE_SRV:
    1180             :         case DNS_TYPE_PTR:
    1181             :         case DNS_TYPE_NS:
    1182             :         case DNS_TYPE_CNAME:
    1183             :         case DNS_TYPE_DNAME:
    1184             :         case DNS_TYPE_HINFO:
    1185             :         case DNS_TYPE_SPF:
    1186             :         case DNS_TYPE_TXT:
    1187             :         case DNS_TYPE_A:
    1188             :         case DNS_TYPE_AAAA:
    1189             :         case DNS_TYPE_SOA:
    1190             :         case DNS_TYPE_MX:
    1191             :         case DNS_TYPE_LOC:
    1192             :         case DNS_TYPE_DS:
    1193             :         case DNS_TYPE_DNSKEY:
    1194             :         case DNS_TYPE_RRSIG:
    1195             :         case DNS_TYPE_NSEC:
    1196             :         case DNS_TYPE_NSEC3:
    1197           0 :                 return -EINVAL;
    1198             : 
    1199           0 :         case DNS_TYPE_SSHFP:
    1200           0 :                 *out = rr->sshfp.fingerprint;
    1201           0 :                 return rr->sshfp.fingerprint_size;
    1202             : 
    1203           0 :         case DNS_TYPE_TLSA:
    1204           0 :                 *out = rr->tlsa.data;
    1205           0 :                 return rr->tlsa.data_size;
    1206             : 
    1207           0 :         case DNS_TYPE_OPENPGPKEY:
    1208             :         default:
    1209           0 :                 *out = rr->generic.data;
    1210           0 :                 return rr->generic.data_size;
    1211             :         }
    1212             : }
    1213             : 
    1214         242 : int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
    1215             : 
    1216         242 :         DnsPacket packet = {
    1217             :                 .n_ref = 1,
    1218             :                 .protocol = DNS_PROTOCOL_DNS,
    1219             :                 .on_stack = true,
    1220             :                 .refuse_compression = true,
    1221             :                 .canonical_form = canonical,
    1222             :         };
    1223             : 
    1224             :         size_t start, rds;
    1225             :         int r;
    1226             : 
    1227         242 :         assert(rr);
    1228             : 
    1229             :         /* Generates the RR in wire-format, optionally in the
    1230             :          * canonical form as discussed in the DNSSEC RFC 4034, Section
    1231             :          * 6.2. We allocate a throw-away DnsPacket object on the stack
    1232             :          * here, because we need some book-keeping for memory
    1233             :          * management, and can reuse the DnsPacket serializer, that
    1234             :          * can generate the canonical form, too, but also knows label
    1235             :          * compression and suchlike. */
    1236             : 
    1237         242 :         if (rr->wire_format && rr->wire_format_canonical == canonical)
    1238           0 :                 return 0;
    1239             : 
    1240         242 :         r = dns_packet_append_rr(&packet, rr, 0, &start, &rds);
    1241         242 :         if (r < 0)
    1242           0 :                 return r;
    1243             : 
    1244         242 :         assert(start == 0);
    1245         242 :         assert(packet._data);
    1246             : 
    1247         242 :         free(rr->wire_format);
    1248         242 :         rr->wire_format = packet._data;
    1249         242 :         rr->wire_format_size = packet.size;
    1250         242 :         rr->wire_format_rdata_offset = rds;
    1251         242 :         rr->wire_format_canonical = canonical;
    1252             : 
    1253         242 :         packet._data = NULL;
    1254         242 :         dns_packet_unref(&packet);
    1255             : 
    1256         242 :         return 0;
    1257             : }
    1258             : 
    1259           0 : int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
    1260             :         const char *n;
    1261             :         int r;
    1262             : 
    1263           0 :         assert(rr);
    1264           0 :         assert(ret);
    1265             : 
    1266             :         /* Returns the RRset's signer, if it is known. */
    1267             : 
    1268           0 :         if (rr->n_skip_labels_signer == (unsigned) -1)
    1269           0 :                 return -ENODATA;
    1270             : 
    1271           0 :         n = dns_resource_key_name(rr->key);
    1272           0 :         r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
    1273           0 :         if (r < 0)
    1274           0 :                 return r;
    1275           0 :         if (r == 0)
    1276           0 :                 return -EINVAL;
    1277             : 
    1278           0 :         *ret = n;
    1279           0 :         return 0;
    1280             : }
    1281             : 
    1282           0 : int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
    1283             :         const char *n;
    1284             :         int r;
    1285             : 
    1286           0 :         assert(rr);
    1287           0 :         assert(ret);
    1288             : 
    1289             :         /* Returns the RRset's synthesizing source, if it is known. */
    1290             : 
    1291           0 :         if (rr->n_skip_labels_source == (unsigned) -1)
    1292           0 :                 return -ENODATA;
    1293             : 
    1294           0 :         n = dns_resource_key_name(rr->key);
    1295           0 :         r = dns_name_skip(n, rr->n_skip_labels_source, &n);
    1296           0 :         if (r < 0)
    1297           0 :                 return r;
    1298           0 :         if (r == 0)
    1299           0 :                 return -EINVAL;
    1300             : 
    1301           0 :         *ret = n;
    1302           0 :         return 0;
    1303             : }
    1304             : 
    1305           0 : int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) {
    1306             :         const char *signer;
    1307             :         int r;
    1308             : 
    1309           0 :         assert(rr);
    1310             : 
    1311           0 :         r = dns_resource_record_signer(rr, &signer);
    1312           0 :         if (r < 0)
    1313           0 :                 return r;
    1314             : 
    1315           0 :         return dns_name_equal(zone, signer);
    1316             : }
    1317             : 
    1318           0 : int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
    1319             :         int r;
    1320             : 
    1321           0 :         assert(rr);
    1322             : 
    1323             :         /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
    1324             : 
    1325           0 :         if (rr->n_skip_labels_source == (unsigned) -1)
    1326           0 :                 return -ENODATA;
    1327             : 
    1328           0 :         if (rr->n_skip_labels_source == 0)
    1329           0 :                 return 0;
    1330             : 
    1331           0 :         if (rr->n_skip_labels_source > 1)
    1332           0 :                 return 1;
    1333             : 
    1334           0 :         r = dns_name_startswith(dns_resource_key_name(rr->key), "*");
    1335           0 :         if (r < 0)
    1336           0 :                 return r;
    1337             : 
    1338           0 :         return !r;
    1339             : }
    1340             : 
    1341         476 : void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *state) {
    1342         476 :         assert(rr);
    1343             : 
    1344         476 :         dns_resource_key_hash_func(rr->key, state);
    1345             : 
    1346         476 :         switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
    1347             : 
    1348           0 :         case DNS_TYPE_SRV:
    1349           0 :                 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
    1350           0 :                 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
    1351           0 :                 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
    1352           0 :                 dns_name_hash_func(rr->srv.name, state);
    1353           0 :                 break;
    1354             : 
    1355         152 :         case DNS_TYPE_PTR:
    1356             :         case DNS_TYPE_NS:
    1357             :         case DNS_TYPE_CNAME:
    1358             :         case DNS_TYPE_DNAME:
    1359         152 :                 dns_name_hash_func(rr->ptr.name, state);
    1360         152 :                 break;
    1361             : 
    1362           0 :         case DNS_TYPE_HINFO:
    1363           0 :                 string_hash_func(rr->hinfo.cpu, state);
    1364           0 :                 string_hash_func(rr->hinfo.os, state);
    1365           0 :                 break;
    1366             : 
    1367          36 :         case DNS_TYPE_TXT:
    1368             :         case DNS_TYPE_SPF: {
    1369             :                 DnsTxtItem *j;
    1370             : 
    1371          72 :                 LIST_FOREACH(items, j, rr->txt.items) {
    1372          36 :                         siphash24_compress(j->data, j->length, state);
    1373             : 
    1374             :                         /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
    1375             :                          * followed by "". */
    1376          36 :                         siphash24_compress_byte(0, state);
    1377             :                 }
    1378          36 :                 break;
    1379             :         }
    1380             : 
    1381          56 :         case DNS_TYPE_A:
    1382          56 :                 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
    1383          56 :                 break;
    1384             : 
    1385          28 :         case DNS_TYPE_AAAA:
    1386          28 :                 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
    1387          28 :                 break;
    1388             : 
    1389          28 :         case DNS_TYPE_SOA:
    1390          28 :                 dns_name_hash_func(rr->soa.mname, state);
    1391          28 :                 dns_name_hash_func(rr->soa.rname, state);
    1392          28 :                 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
    1393          28 :                 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
    1394          28 :                 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
    1395          28 :                 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
    1396          28 :                 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
    1397          28 :                 break;
    1398             : 
    1399          56 :         case DNS_TYPE_MX:
    1400          56 :                 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
    1401          56 :                 dns_name_hash_func(rr->mx.exchange, state);
    1402          56 :                 break;
    1403             : 
    1404          12 :         case DNS_TYPE_LOC:
    1405          12 :                 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
    1406          12 :                 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
    1407          12 :                 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
    1408          12 :                 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
    1409          12 :                 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
    1410          12 :                 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
    1411          12 :                 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
    1412          12 :                 break;
    1413             : 
    1414          24 :         case DNS_TYPE_SSHFP:
    1415          24 :                 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
    1416          24 :                 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
    1417          24 :                 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
    1418          24 :                 break;
    1419             : 
    1420          32 :         case DNS_TYPE_DNSKEY:
    1421          32 :                 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
    1422          32 :                 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
    1423          32 :                 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
    1424          32 :                 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
    1425          32 :                 break;
    1426             : 
    1427           0 :         case DNS_TYPE_RRSIG:
    1428           0 :                 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
    1429           0 :                 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
    1430           0 :                 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
    1431           0 :                 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
    1432           0 :                 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
    1433           0 :                 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
    1434           0 :                 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
    1435           0 :                 dns_name_hash_func(rr->rrsig.signer, state);
    1436           0 :                 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
    1437           0 :                 break;
    1438             : 
    1439          24 :         case DNS_TYPE_NSEC:
    1440          24 :                 dns_name_hash_func(rr->nsec.next_domain_name, state);
    1441             :                 /* FIXME: we leave out the type bitmap here. Hash
    1442             :                  * would be better if we'd take it into account
    1443             :                  * too. */
    1444          24 :                 break;
    1445             : 
    1446           0 :         case DNS_TYPE_DS:
    1447           0 :                 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
    1448           0 :                 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
    1449           0 :                 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
    1450           0 :                 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
    1451           0 :                 break;
    1452             : 
    1453           0 :         case DNS_TYPE_NSEC3:
    1454           0 :                 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
    1455           0 :                 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
    1456           0 :                 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
    1457           0 :                 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
    1458           0 :                 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
    1459             :                 /* FIXME: We leave the bitmaps out */
    1460           0 :                 break;
    1461             : 
    1462           4 :         case DNS_TYPE_TLSA:
    1463           4 :                 siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
    1464           4 :                 siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
    1465           4 :                 siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
    1466           4 :                 siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state);
    1467           4 :                 break;
    1468             : 
    1469          20 :         case DNS_TYPE_CAA:
    1470          20 :                 siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state);
    1471          20 :                 string_hash_func(rr->caa.tag, state);
    1472          20 :                 siphash24_compress(rr->caa.value, rr->caa.value_size, state);
    1473          20 :                 break;
    1474             : 
    1475           4 :         case DNS_TYPE_OPENPGPKEY:
    1476             :         default:
    1477           4 :                 siphash24_compress(rr->generic.data, rr->generic.data_size, state);
    1478           4 :                 break;
    1479             :         }
    1480         476 : }
    1481             : 
    1482           0 : static int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y) {
    1483             :         int r;
    1484             : 
    1485           0 :         r = dns_resource_key_compare_func(x->key, y->key);
    1486           0 :         if (r != 0)
    1487           0 :                 return r;
    1488             : 
    1489           0 :         if (dns_resource_record_equal(x, y))
    1490           0 :                 return 0;
    1491             : 
    1492             :         /* We still use CMP() here, even though don't implement proper
    1493             :          * ordering, since the hashtable doesn't need ordering anyway. */
    1494           0 :         return CMP(x, y);
    1495             : }
    1496             : 
    1497             : DEFINE_HASH_OPS(dns_resource_record_hash_ops, DnsResourceRecord, dns_resource_record_hash_func, dns_resource_record_compare_func);
    1498             : 
    1499         476 : DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) {
    1500         476 :         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *copy = NULL;
    1501             :         DnsResourceRecord *t;
    1502             : 
    1503         476 :         assert(rr);
    1504             : 
    1505         476 :         copy = dns_resource_record_new(rr->key);
    1506         476 :         if (!copy)
    1507           0 :                 return NULL;
    1508             : 
    1509         476 :         copy->ttl = rr->ttl;
    1510         476 :         copy->expiry = rr->expiry;
    1511         476 :         copy->n_skip_labels_signer = rr->n_skip_labels_signer;
    1512         476 :         copy->n_skip_labels_source = rr->n_skip_labels_source;
    1513         476 :         copy->unparseable = rr->unparseable;
    1514             : 
    1515         476 :         switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
    1516             : 
    1517           0 :         case DNS_TYPE_SRV:
    1518           0 :                 copy->srv.priority = rr->srv.priority;
    1519           0 :                 copy->srv.weight = rr->srv.weight;
    1520           0 :                 copy->srv.port = rr->srv.port;
    1521           0 :                 copy->srv.name = strdup(rr->srv.name);
    1522           0 :                 if (!copy->srv.name)
    1523           0 :                         return NULL;
    1524           0 :                 break;
    1525             : 
    1526         152 :         case DNS_TYPE_PTR:
    1527             :         case DNS_TYPE_NS:
    1528             :         case DNS_TYPE_CNAME:
    1529             :         case DNS_TYPE_DNAME:
    1530         152 :                 copy->ptr.name = strdup(rr->ptr.name);
    1531         152 :                 if (!copy->ptr.name)
    1532           0 :                         return NULL;
    1533         152 :                 break;
    1534             : 
    1535           0 :         case DNS_TYPE_HINFO:
    1536           0 :                 copy->hinfo.cpu = strdup(rr->hinfo.cpu);
    1537           0 :                 if (!copy->hinfo.cpu)
    1538           0 :                         return NULL;
    1539             : 
    1540           0 :                 copy->hinfo.os = strdup(rr->hinfo.os);
    1541           0 :                 if (!copy->hinfo.os)
    1542           0 :                         return NULL;
    1543           0 :                 break;
    1544             : 
    1545          36 :         case DNS_TYPE_TXT:
    1546             :         case DNS_TYPE_SPF:
    1547          36 :                 copy->txt.items = dns_txt_item_copy(rr->txt.items);
    1548          36 :                 if (!copy->txt.items)
    1549           0 :                         return NULL;
    1550          36 :                 break;
    1551             : 
    1552          56 :         case DNS_TYPE_A:
    1553          56 :                 copy->a = rr->a;
    1554          56 :                 break;
    1555             : 
    1556          28 :         case DNS_TYPE_AAAA:
    1557          28 :                 copy->aaaa = rr->aaaa;
    1558          28 :                 break;
    1559             : 
    1560          28 :         case DNS_TYPE_SOA:
    1561          28 :                 copy->soa.mname = strdup(rr->soa.mname);
    1562          28 :                 if (!copy->soa.mname)
    1563           0 :                         return NULL;
    1564          28 :                 copy->soa.rname = strdup(rr->soa.rname);
    1565          28 :                 if (!copy->soa.rname)
    1566           0 :                         return NULL;
    1567          28 :                 copy->soa.serial = rr->soa.serial;
    1568          28 :                 copy->soa.refresh = rr->soa.refresh;
    1569          28 :                 copy->soa.retry = rr->soa.retry;
    1570          28 :                 copy->soa.expire = rr->soa.expire;
    1571          28 :                 copy->soa.minimum = rr->soa.minimum;
    1572          28 :                 break;
    1573             : 
    1574          56 :         case DNS_TYPE_MX:
    1575          56 :                 copy->mx.priority = rr->mx.priority;
    1576          56 :                 copy->mx.exchange = strdup(rr->mx.exchange);
    1577          56 :                 if (!copy->mx.exchange)
    1578           0 :                         return NULL;
    1579          56 :                 break;
    1580             : 
    1581          12 :         case DNS_TYPE_LOC:
    1582          12 :                 copy->loc = rr->loc;
    1583          12 :                 break;
    1584             : 
    1585          24 :         case DNS_TYPE_SSHFP:
    1586          24 :                 copy->sshfp.algorithm = rr->sshfp.algorithm;
    1587          24 :                 copy->sshfp.fptype = rr->sshfp.fptype;
    1588          24 :                 copy->sshfp.fingerprint = memdup(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
    1589          24 :                 if (!copy->sshfp.fingerprint)
    1590           0 :                         return NULL;
    1591          24 :                 copy->sshfp.fingerprint_size = rr->sshfp.fingerprint_size;
    1592          24 :                 break;
    1593             : 
    1594          32 :         case DNS_TYPE_DNSKEY:
    1595          32 :                 copy->dnskey.flags = rr->dnskey.flags;
    1596          32 :                 copy->dnskey.protocol = rr->dnskey.protocol;
    1597          32 :                 copy->dnskey.algorithm = rr->dnskey.algorithm;
    1598          32 :                 copy->dnskey.key = memdup(rr->dnskey.key, rr->dnskey.key_size);
    1599          32 :                 if (!copy->dnskey.key)
    1600           0 :                         return NULL;
    1601          32 :                 copy->dnskey.key_size = rr->dnskey.key_size;
    1602          32 :                 break;
    1603             : 
    1604           0 :         case DNS_TYPE_RRSIG:
    1605           0 :                 copy->rrsig.type_covered = rr->rrsig.type_covered;
    1606           0 :                 copy->rrsig.algorithm = rr->rrsig.algorithm;
    1607           0 :                 copy->rrsig.labels = rr->rrsig.labels;
    1608           0 :                 copy->rrsig.original_ttl = rr->rrsig.original_ttl;
    1609           0 :                 copy->rrsig.expiration = rr->rrsig.expiration;
    1610           0 :                 copy->rrsig.inception = rr->rrsig.inception;
    1611           0 :                 copy->rrsig.key_tag = rr->rrsig.key_tag;
    1612           0 :                 copy->rrsig.signer = strdup(rr->rrsig.signer);
    1613           0 :                 if (!copy->rrsig.signer)
    1614           0 :                         return NULL;
    1615           0 :                 copy->rrsig.signature = memdup(rr->rrsig.signature, rr->rrsig.signature_size);
    1616           0 :                 if (!copy->rrsig.signature)
    1617           0 :                         return NULL;
    1618           0 :                 copy->rrsig.signature_size = rr->rrsig.signature_size;
    1619           0 :                 break;
    1620             : 
    1621          24 :         case DNS_TYPE_NSEC:
    1622          24 :                 copy->nsec.next_domain_name = strdup(rr->nsec.next_domain_name);
    1623          24 :                 if (!copy->nsec.next_domain_name)
    1624           0 :                         return NULL;
    1625          24 :                 copy->nsec.types = bitmap_copy(rr->nsec.types);
    1626          24 :                 if (!copy->nsec.types)
    1627           0 :                         return NULL;
    1628          24 :                 break;
    1629             : 
    1630           0 :         case DNS_TYPE_DS:
    1631           0 :                 copy->ds.key_tag = rr->ds.key_tag;
    1632           0 :                 copy->ds.algorithm = rr->ds.algorithm;
    1633           0 :                 copy->ds.digest_type = rr->ds.digest_type;
    1634           0 :                 copy->ds.digest = memdup(rr->ds.digest, rr->ds.digest_size);
    1635           0 :                 if (!copy->ds.digest)
    1636           0 :                         return NULL;
    1637           0 :                 copy->ds.digest_size = rr->ds.digest_size;
    1638           0 :                 break;
    1639             : 
    1640           0 :         case DNS_TYPE_NSEC3:
    1641           0 :                 copy->nsec3.algorithm = rr->nsec3.algorithm;
    1642           0 :                 copy->nsec3.flags = rr->nsec3.flags;
    1643           0 :                 copy->nsec3.iterations = rr->nsec3.iterations;
    1644           0 :                 copy->nsec3.salt = memdup(rr->nsec3.salt, rr->nsec3.salt_size);
    1645           0 :                 if (!copy->nsec3.salt)
    1646           0 :                         return NULL;
    1647           0 :                 copy->nsec3.salt_size = rr->nsec3.salt_size;
    1648           0 :                 copy->nsec3.next_hashed_name = memdup(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size);
    1649           0 :                 if (!copy->nsec3.next_hashed_name_size)
    1650           0 :                         return NULL;
    1651           0 :                 copy->nsec3.next_hashed_name_size = rr->nsec3.next_hashed_name_size;
    1652           0 :                 copy->nsec3.types = bitmap_copy(rr->nsec3.types);
    1653           0 :                 if (!copy->nsec3.types)
    1654           0 :                         return NULL;
    1655           0 :                 break;
    1656             : 
    1657           4 :         case DNS_TYPE_TLSA:
    1658           4 :                 copy->tlsa.cert_usage = rr->tlsa.cert_usage;
    1659           4 :                 copy->tlsa.selector = rr->tlsa.selector;
    1660           4 :                 copy->tlsa.matching_type = rr->tlsa.matching_type;
    1661           4 :                 copy->tlsa.data = memdup(rr->tlsa.data, rr->tlsa.data_size);
    1662           4 :                 if (!copy->tlsa.data)
    1663           0 :                         return NULL;
    1664           4 :                 copy->tlsa.data_size = rr->tlsa.data_size;
    1665           4 :                 break;
    1666             : 
    1667          20 :         case DNS_TYPE_CAA:
    1668          20 :                 copy->caa.flags = rr->caa.flags;
    1669          20 :                 copy->caa.tag = strdup(rr->caa.tag);
    1670          20 :                 if (!copy->caa.tag)
    1671           0 :                         return NULL;
    1672          20 :                 copy->caa.value = memdup(rr->caa.value, rr->caa.value_size);
    1673          20 :                 if (!copy->caa.value)
    1674           0 :                         return NULL;
    1675          20 :                 copy->caa.value_size = rr->caa.value_size;
    1676          20 :                 break;
    1677             : 
    1678           4 :         case DNS_TYPE_OPT:
    1679             :         default:
    1680           4 :                 copy->generic.data = memdup(rr->generic.data, rr->generic.data_size);
    1681           4 :                 if (!copy->generic.data)
    1682           0 :                         return NULL;
    1683           4 :                 copy->generic.data_size = rr->generic.data_size;
    1684           4 :                 break;
    1685             :         }
    1686             : 
    1687         476 :         t = TAKE_PTR(copy);
    1688             : 
    1689         476 :         return t;
    1690             : }
    1691             : 
    1692           0 : int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) {
    1693             :         DnsResourceRecord *old_rr, *new_rr;
    1694             :         uint32_t new_ttl;
    1695             : 
    1696           0 :         assert(rr);
    1697           0 :         old_rr = *rr;
    1698             : 
    1699           0 :         if (old_rr->key->type == DNS_TYPE_OPT)
    1700           0 :                 return -EINVAL;
    1701             : 
    1702           0 :         new_ttl = MIN(old_rr->ttl, max_ttl);
    1703           0 :         if (new_ttl == old_rr->ttl)
    1704           0 :                 return 0;
    1705             : 
    1706           0 :         if (old_rr->n_ref == 1) {
    1707             :                 /* Patch in place */
    1708           0 :                 old_rr->ttl = new_ttl;
    1709           0 :                 return 1;
    1710             :         }
    1711             : 
    1712           0 :         new_rr = dns_resource_record_copy(old_rr);
    1713           0 :         if (!new_rr)
    1714           0 :                 return -ENOMEM;
    1715             : 
    1716           0 :         new_rr->ttl = new_ttl;
    1717             : 
    1718           0 :         dns_resource_record_unref(*rr);
    1719           0 :         *rr = new_rr;
    1720             : 
    1721           0 :         return 1;
    1722             : }
    1723             : 
    1724         144 : DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
    1725             :         DnsTxtItem *n;
    1726             : 
    1727         144 :         if (!i)
    1728          72 :                 return NULL;
    1729             : 
    1730          72 :         n = i->items_next;
    1731             : 
    1732          72 :         free(i);
    1733          72 :         return dns_txt_item_free_all(n);
    1734             : }
    1735             : 
    1736          72 : bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
    1737             : 
    1738          72 :         if (a == b)
    1739          36 :                 return true;
    1740             : 
    1741          36 :         if (!a != !b)
    1742           0 :                 return false;
    1743             : 
    1744          36 :         if (!a)
    1745           0 :                 return true;
    1746             : 
    1747          36 :         if (a->length != b->length)
    1748           0 :                 return false;
    1749             : 
    1750          36 :         if (memcmp(a->data, b->data, a->length) != 0)
    1751           0 :                 return false;
    1752             : 
    1753          36 :         return dns_txt_item_equal(a->items_next, b->items_next);
    1754             : }
    1755             : 
    1756          36 : DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) {
    1757          36 :         DnsTxtItem *i, *copy = NULL, *end = NULL;
    1758             : 
    1759          72 :         LIST_FOREACH(items, i, first) {
    1760             :                 DnsTxtItem *j;
    1761             : 
    1762          36 :                 j = memdup(i, offsetof(DnsTxtItem, data) + i->length + 1);
    1763          36 :                 if (!j) {
    1764           0 :                         dns_txt_item_free_all(copy);
    1765           0 :                         return NULL;
    1766             :                 }
    1767             : 
    1768          36 :                 LIST_INSERT_AFTER(items, copy, end, j);
    1769          36 :                 end = j;
    1770             :         }
    1771             : 
    1772          36 :         return copy;
    1773             : }
    1774             : 
    1775           0 : int dns_txt_item_new_empty(DnsTxtItem **ret) {
    1776             :         DnsTxtItem *i;
    1777             : 
    1778             :         /* RFC 6763, section 6.1 suggests to treat
    1779             :          * empty TXT RRs as equivalent to a TXT record
    1780             :          * with a single empty string. */
    1781             : 
    1782           0 :         i = malloc0(offsetof(DnsTxtItem, data) + 1); /* for safety reasons we add an extra NUL byte */
    1783           0 :         if (!i)
    1784           0 :                 return -ENOMEM;
    1785             : 
    1786           0 :         *ret = i;
    1787             : 
    1788           0 :         return 0;
    1789             : }
    1790             : 
    1791             : static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
    1792             :         /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
    1793             :         [DNSSEC_ALGORITHM_RSAMD5]             = "RSAMD5",
    1794             :         [DNSSEC_ALGORITHM_DH]                 = "DH",
    1795             :         [DNSSEC_ALGORITHM_DSA]                = "DSA",
    1796             :         [DNSSEC_ALGORITHM_ECC]                = "ECC",
    1797             :         [DNSSEC_ALGORITHM_RSASHA1]            = "RSASHA1",
    1798             :         [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1]     = "DSA-NSEC3-SHA1",
    1799             :         [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
    1800             :         [DNSSEC_ALGORITHM_RSASHA256]          = "RSASHA256",
    1801             :         [DNSSEC_ALGORITHM_RSASHA512]          = "RSASHA512",
    1802             :         [DNSSEC_ALGORITHM_ECC_GOST]           = "ECC-GOST",
    1803             :         [DNSSEC_ALGORITHM_ECDSAP256SHA256]    = "ECDSAP256SHA256",
    1804             :         [DNSSEC_ALGORITHM_ECDSAP384SHA384]    = "ECDSAP384SHA384",
    1805             :         [DNSSEC_ALGORITHM_ED25519]            = "ED25519",
    1806             :         [DNSSEC_ALGORITHM_ED448]              = "ED448",
    1807             :         [DNSSEC_ALGORITHM_INDIRECT]           = "INDIRECT",
    1808             :         [DNSSEC_ALGORITHM_PRIVATEDNS]         = "PRIVATEDNS",
    1809             :         [DNSSEC_ALGORITHM_PRIVATEOID]         = "PRIVATEOID",
    1810             : };
    1811          57 : DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
    1812             : 
    1813             : static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
    1814             :         /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
    1815             :         [DNSSEC_DIGEST_SHA1] = "SHA-1",
    1816             :         [DNSSEC_DIGEST_SHA256] = "SHA-256",
    1817             :         [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
    1818             :         [DNSSEC_DIGEST_SHA384] = "SHA-384",
    1819             : };
    1820           0 : DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);

Generated by: LCOV version 1.14