static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *rr) {
        int r;

        assert(t);
        assert(rr);

        /* Checks if the RR we are looking for must be signed with an
         * RRSIG. This is used for positive responses. */

        if (t->scope->dnssec_mode == DNSSEC_NO)
                return false;

        if (dns_type_is_pseudo(rr->key->type))
                return -EINVAL;

        r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
        if (r < 0)
                return r;
        if (r > 0)
                return false;

        switch (rr->key->type) {

        case DNS_TYPE_RRSIG:
                /* RRSIGs are the signatures themselves, they need no signing. */
                return false;

        case DNS_TYPE_SOA:
        case DNS_TYPE_NS: {
                DnsTransaction *dt;
                Iterator i;

                /* For SOA or NS RRs we look for a matching DS transaction */

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_DS)
                                continue;

                        r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                        /* We found a DS transactions for the SOA/NS
                         * RRs we are looking at. If it discovered signed DS
                         * RRs, then we need to be signed, too. */

                        if (!dt->answer_authenticated)
                                return false;

                        return dns_answer_match_key(dt->answer, dt->key, NULL);
                }

                /* We found nothing that proves this is safe to leave
                 * this unauthenticated, hence ask inist on
                 * authentication. */
                return true;
        }

        case DNS_TYPE_DS:
        case DNS_TYPE_CNAME:
        case DNS_TYPE_DNAME: {
                const char *parent = NULL;
                DnsTransaction *dt;
                Iterator i;

                /*
                 * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent SOA.
                 *
                 * DS RRs are signed if the parent is signed, hence also look at the parent SOA
                 */

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_SOA)
                                continue;

                        if (!parent) {
                                parent = dns_resource_key_name(rr->key);
                                r = dns_name_parent(&parent);
                                if (r < 0)
                                        return r;
                                if (r == 0) {
                                        if (rr->key->type == DNS_TYPE_DS)
                                                return true;

                                        /* A CNAME/DNAME without a parent? That's sooo weird. */
                                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
                                                               "Transaction %" PRIu16 " claims CNAME/DNAME at root. Refusing.", t->id);
                                }
                        }

                        r = dns_name_equal(dns_resource_key_name(dt->key), parent);
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                        return t->answer_authenticated;
                }

                return true;
        }

        default: {
                DnsTransaction *dt;
                Iterator i;

                /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our SOA lookup was authenticated */

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_SOA)
                                continue;

                        r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                        /* We found the transaction that was supposed to find
                         * the SOA RR for us. It was successful, but found no
                         * RR for us. This means we are not at a zone cut. In
                         * this case, we require authentication if the SOA
                         * lookup was authenticated too. */
                        return t->answer_authenticated;
                }

                return true;
        }}
}
static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *rr) {
        int r;

        assert(t);
        assert(rr);

         

        if (t->scope->dnssec_mode == DNSSEC_NO)
                return false;

        if (dns_type_is_pseudo(rr->key->type))
                return -EINVAL;

        r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
        if (r < 0)
                return r;
        if (r > 0)
                return false;

        switch (rr->key->type) {

        case DNS_TYPE_RRSIG:
                 
                return false;

        case DNS_TYPE_SOA:
        case DNS_TYPE_NS: {
                DnsTransaction *dt;
                Iterator i;

                 

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_DS)
                                continue;

                        r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                         

                        if (!dt->answer_authenticated)
                                return false;

                        return dns_answer_match_key(dt->answer, dt->key, NULL);
                }

                 
                return true;
        }

        case DNS_TYPE_DS:
        case DNS_TYPE_CNAME:
        case DNS_TYPE_DNAME: {
                const char *parent = NULL;
                DnsTransaction *dt;
                Iterator i;

                 

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_SOA)
                                continue;

                        if (!parent) {
                                parent = dns_resource_key_name(rr->key);
                                r = dns_name_parent(&parent);
                                if (r < 0)
                                        return r;
                                if (r == 0) {
                                        if (rr->key->type == DNS_TYPE_DS)
                                                return true;

                                         
                                        return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
                                                               "Transaction %" PRIu16 " claims CNAME/DNAME at root. Refusing.", t->id);
                                }
                        }

                        r = dns_name_equal(dns_resource_key_name(dt->key), parent);
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                        return t->answer_authenticated;
                }

                return true;
        }

        default: {
                DnsTransaction *dt;
                Iterator i;

                 

                SET_FOREACH(dt, t->dnssec_transactions, i) {

                        if (dt->key->class != rr->key->class)
                                continue;
                        if (dt->key->type != DNS_TYPE_SOA)
                                continue;

                        r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
                        if (r < 0)
                                return r;
                        if (r == 0)
                                continue;

                         
                        return t->answer_authenticated;
                }

                return true;
        }}
}