Exemplo n.º 1
0
/**
 * @return 成功した場合は NETDB_SUCCESS.
 */
static int
DnsResolver_lookupTxtData(DnsResolver *self, int rrtype, const char *domain, DnsTxtResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, rrtype);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsTxtResponse *respobj =
        (DnsTxtResponse *) malloc(sizeof(DnsTxtResponse) + msg_count * sizeof(char *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsTxtResponse) + msg_count * sizeof(char *));
    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_txt != ns_rr_type(rr)) {
            continue;
        }   // end if
        respobj->data[respobj->num] = (char *) malloc(ns_rr_rdlen(rr)); // RDLEN を越えることはない.
        if (NULL == respobj->data[respobj->num]) {
            goto noresource;
        }   // end if
        const unsigned char *rdata = ns_rr_rdata(rr);
        const unsigned char *rdata_tail = ns_rr_rdata(rr) + ns_rr_rdlen(rr);
        char *bufp = respobj->data[respobj->num];
        while (rdata < rdata_tail) {
            // 長さフィールドが RDLEN の中に収まっているか確認する
            if (rdata_tail < rdata + (*rdata) + 1) {
                free(respobj->data[respobj->num]);
                goto formerr;
            }   // end if
            memcpy(bufp, rdata + 1, *rdata);
            bufp += (size_t) *rdata;
            rdata += (size_t) *rdata + 1;
        }   // end while
        *bufp = '\0';   // 扱いやすいように NULL 終端させる
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

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

  noresource:
    DnsTxtResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupTxtData
Exemplo n.º 2
0
void
DnsSpfResponse_free(DnsSpfResponse *self)
{
    DnsTxtResponse_free(self);
}   // end function : DnsSpfResponse_free
Exemplo n.º 3
0
/**
 * @return DSTAT_OK for success, otherwise status code that indicates error.
 * @error DSTAT_INFO_ADSP_NOT_EXIST ADSP record have not found
 * @error DSTAT_PERMFAIL_MULTIPLE_ADSP_RECORD multiple ADSP records are found
 * @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
 * @error DSTAT_SYSERR_NORESOURCE memory allocation error
 */
static DkimAdsp *
DkimAdsp_query(const DkimPolicyBase *policy, DnsResolver *resolver, const char *domain,
               DkimStatus *dstat)
{
    assert(NULL != resolver);
    assert(NULL != domain);

    // lookup ADSP record
    DnsTxtResponse *txt_rr = NULL;
    dns_stat_t txtquery_stat = DnsResolver_lookupTxt(resolver, domain, &txt_rr);
    switch (txtquery_stat) {
    case DNS_STAT_NOERROR:;
        // a TXT RR is found

        /*
         * [RFC5617] 4.3.
         * If the result of this query is a NOERROR response (rcode=0 in
         * [RFC1035]) with an answer that is a single record that is a valid
         * ADSP record, use that record, and the algorithm terminates.
         */
        if (0 == DnsTxtResponse_size(txt_rr)) {
            // no TXT records are found
            DnsTxtResponse_free(txt_rr);
            SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST);
            break;
        } else if (1 < DnsTxtResponse_size(txt_rr)) {
            // multiple TXT records are found
            DnsTxtResponse_free(txt_rr);
            SETDEREF(dstat, DSTAT_PERMFAIL_MULTIPLE_ADSP_RECORD);
            break;
        }   // end if

        // only one TXT record is found, and now, try to parse as ADSP record
        DkimStatus build_stat;
        const char *txtrecord = DnsTxtResponse_data(txt_rr, 0);
        DkimAdsp *self = DkimAdsp_build(policy, txtrecord, &build_stat);
        if (NULL != self) {
            // parsed as a valid ADSP record
            DnsTxtResponse_free(txt_rr);
            SETDEREF(dstat, DSTAT_OK);
            return self;
        } else if (DSTAT_ISCRITERR(build_stat)) {
            // propagate system errors as-is
            DkimLogSysError
                (policy,
                 "System error has occurred while parsing ADSP record: domain=%s, err=%s, record=%s",
                 domain, DKIM_strerror(build_stat), NNSTR(txtrecord));
            SETDEREF(dstat, build_stat);
        } else if (DSTAT_ISPERMFAIL(build_stat)) {
            /*
             * treat syntax errors on ADSP record as DNS NODATA response
             *
             * [RFC5617] 4.1.
             * Records not in compliance with that syntax
             * or the syntax of individual tags described in Section 4.3 MUST be
             * ignored (considered equivalent to a NODATA result) for purposes of
             * ADSP, although they MAY cause the logging of warning messages via an
             * appropriate system logging mechanism.
             */
            DkimLogDebug(policy, "ADSP record candidate discarded: domain=%s, err=%s, record=%s",
                         domain, DKIM_strerror(build_stat), NNSTR(txtrecord));
            SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST);
        } else {
            DkimLogNotice(policy, "DkimAdsp_build failed: domain=%s, err=%s, record=%s",
                          domain, DKIM_strerror(build_stat), NNSTR(txtrecord));
            SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST);
        }   // end if

        // a TXT RR is not a valid ADSP record
        DnsTxtResponse_free(txt_rr);
        break;

    case DNS_STAT_NXDOMAIN:
    case DNS_STAT_NODATA:
        /*
         * no TXT (and ADSP) records are found
         *
         * [RFC5617] 4.3.
         * If the result of the query is NXDOMAIN or NOERROR with zero
         * records, there is no ADSP record.  If the result of the query
         * contains more than one record, or a record that is not a valid
         * ADSP record, the ADSP result is undefined.
         */
        DkimLogDebug(policy, "No ADSP record is found on DNS: domain=%s", domain);
        SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST);
        break;

    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:
        /*
         * [RFC5617] 4.3.
         * If a query results in a "SERVFAIL" error response (rcode=2 in
         * [RFC1035]), the algorithm terminates without returning a result;
         * possible actions include queuing the message or returning an SMTP
         * error indicating a temporary failure.
         */
        DkimLogInfo(policy, "DNS error on ADSP record look-up: domain=%s, type=txt, err=%s",
                    domain, DnsResolver_getErrorString(resolver));
        SETDEREF(dstat, DSTAT_TMPERR_DNS_ERROR_RESPONSE);
        break;

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

    case DNS_STAT_NOMEMORY:
        DkimLogNoResource(policy);
        SETDEREF(dstat, DSTAT_SYSERR_NORESOURCE);
        break;

    case DNS_STAT_BADREQUEST:
    default:
        DkimLogImplError(policy,
                         "DnsResolver_lookupTxt returns unexpected value: value=0x%x, domain=%s, type=txt",
                         txtquery_stat, domain);
        SETDEREF(dstat, DSTAT_SYSERR_IMPLERROR);
        break;
    }   // end switch

    return NULL;
}   // end function: DkimAdsp_query