Esempio n. 1
0
int
DnsResolver_lookupMx(DnsResolver *self, const char *domain, DnsMxResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, ns_t_mx);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsMxResponse *respobj =
        (DnsMxResponse *) malloc(sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_mx != ns_rr_type(rr)) {
            continue;
        }   // end if
        const unsigned char *rdata = ns_rr_rdata(rr);
        if (ns_rr_rdlen(rr) < NS_INT16SZ) {
            goto formerr;
        }   // end if

        int preference = ns_get16(rdata);
        rdata += NS_INT16SZ;

        // NOTE: NS_MAXDNAME で十分なのかイマイチ確証が持てないが, bind8 の dig コマンドの実装でもこの値を使っていたのでいいのではないか.
        char dnamebuf[NS_MAXDNAME];
        int dnamelen =
            ns_name_uncompress(self->msgbuf, self->msgbuf + self->msglen, rdata, dnamebuf,
                               sizeof(dnamebuf));
        if (NS_INT16SZ + dnamelen != ns_rr_rdlen(rr)) {
            goto formerr;
        }   // end if
        // TODO: dnamebuf は NULL 終端が保証されているのか?
        size_t domainlen = strlen(dnamebuf);
        respobj->exchange[respobj->num] =
            (struct mxentry *) malloc(sizeof(struct mxentry) + sizeof(char[domainlen + 1]));
        if (NULL == respobj->exchange[respobj->num]) {
            goto noresource;
        }   // end if
        respobj->exchange[respobj->num]->preference = preference;
        if (domainlen + 1 <=
            strlcpy(respobj->exchange[respobj->num]->domain, dnamebuf, domainlen + 1)) {
            abort();
        }   // end if
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);

  noresource:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupMx
Esempio n. 2
0
/**
 * Check whether a given Author Domain is within scope for ADSP.
 * @return DSTAT_OK for success, otherwise status code that indicates error.
 * @error DSTAT_INFO_ADSP_NXDOMAIN Author Domain does not exist (NXDOMAIN)
 * @error DSTAT_TMPERR_DNS_ERROR_RESPONSE DNS lookup error (received error response)
 * @error DSTAT_SYSERR_DNS_LOOKUP_FAILURE DNS lookup error (failed to lookup itself)
 * @error DSTAT_SYSERR_IMPLERROR obvious implementation error
 */
static DkimStatus
DkimAdsp_checkDomainScope(const DkimPolicyBase *policy, DnsResolver *resolver, const char *domain)
{
    assert(NULL != resolver);
    assert(NULL != domain);

    /*
     * [RFC5617] 4.3.
     * The host MUST perform a DNS query for a record corresponding to
     * the Author Domain (with no prefix).  The type of the query can be
     * of any type, since this step is only to determine if the domain
     * itself exists in DNS.  This query MAY be done in parallel with the
     * query to fetch the named ADSP Record.  If the result of this query
     * is that the Author Domain does not exist in the DNS (often called
     * an NXDOMAIN error, rcode=3 in [RFC1035]), the algorithm MUST
     * terminate with an error indicating that the domain is out of
     * scope.  Note that a result with rcode=0 but no records (often
     * called NODATA) is not the same as NXDOMAIN.
     *
     *    NON-NORMATIVE DISCUSSION: Any resource record type could be
     *    used for this query since the existence of a resource record of
     *    any type will prevent an NXDOMAIN error.  MX is a reasonable
     *    choice for this purpose because this record type is thought to
     *    be the most common for domains used in email, and will
     *    therefore produce a result that can be more readily cached than
     *    a negative result.
     */

    DnsMxResponse *mx_rr = NULL;
    dns_stat_t mxquery_stat = DnsResolver_lookupMx(resolver, domain, &mx_rr);
    switch (mxquery_stat) {
    case DNS_STAT_NOERROR:
        DnsMxResponse_free(mx_rr);
        // fall through

    case DNS_STAT_NODATA:
        return DSTAT_OK;

    case DNS_STAT_NXDOMAIN:
        DkimLogPermFail(policy, "The author domain does not exist: domain=%s, type=mx, err=%s",
                        domain, DnsResolver_getErrorString(resolver));
        return DSTAT_INFO_ADSP_NXDOMAIN;

    case DNS_STAT_FORMERR:
    case DNS_STAT_SERVFAIL:
    case DNS_STAT_NOTIMPL:
    case DNS_STAT_REFUSED:
    case DNS_STAT_YXDOMAIN:
    case DNS_STAT_YXRRSET:
    case DNS_STAT_NXRRSET:
    case DNS_STAT_NOTAUTH:
    case DNS_STAT_NOTZONE:
    case DNS_STAT_RESERVED11:
    case DNS_STAT_RESERVED12:
    case DNS_STAT_RESERVED13:
    case DNS_STAT_RESERVED14:
    case DNS_STAT_RESERVED15:
        DkimLogPermFail(policy,
                        "DNS error on checking author domain existence: domain=%s, type=mx, err=%s",
                        domain, DnsResolver_getErrorString(resolver));
        return DSTAT_TMPERR_DNS_ERROR_RESPONSE;

    case DNS_STAT_SYSTEM:
    case DNS_STAT_RESOLVER:
    case DNS_STAT_RESOLVER_INTERNAL:
        DkimLogSysError(policy, "error occurred during DNS lookup: domain=%s, type=mx, err=%s",
                        domain, DnsResolver_getErrorString(resolver));
        return DSTAT_SYSERR_DNS_LOOKUP_FAILURE;

    case DNS_STAT_NOMEMORY:
        DkimLogNoResource(policy);
        return DSTAT_SYSERR_NORESOURCE;

    case DNS_STAT_BADREQUEST:
    default:
        DkimLogImplError(policy,
                         "DnsResolver_lookupMx returns unexpected value: value=0x%x, domain=%s, type=mx",
                         mxquery_stat, domain);
        return DSTAT_SYSERR_IMPLERROR;
    }   // end switch
}   // end function: DkimAdsp_checkDomainScope