Back to index

opendkim  2.6.2
opendkim-dns.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2008 Sendmail, Inc. and its suppliers.
00003 **    All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2012, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char opendkim_dns_c_id[] = "@(#)$Id: opendkim-dns.c,v 1.7.10.2 2010/10/28 04:28:04 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 #include "build-config.h"
00013 
00014 /* system includes */
00015 #include <sys/types.h>
00016 #include <sys/time.h>
00017 #include <netinet/in.h>
00018 #include <arpa/nameser.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <assert.h>
00022 #include <pthread.h>
00023 #include <resolv.h>
00024 #include <errno.h>
00025 
00026 /* libopendkim includes */
00027 #include <dkim.h>
00028 
00029 #ifdef _FFR_DKIM_REPUTATION
00030 /* libdkimrep includes */
00031 # include <dkim-rep.h>
00032 #endif /* _FFR_DKIM_REPUTATION */
00033 
00034 #ifdef USE_UNBOUND
00035 /* libunbound includes */
00036 # include <unbound.h>
00037 #endif /* USE_UNBOUND */
00038 
00039 #ifdef _FFR_RBL
00040 /* librbl includes */
00041 # include <rbl.h>
00042 #endif /* _FFR_RBL */
00043 
00044 #ifdef USE_ARLIB
00045 /* libar includes */
00046 # include <async-resolv.h>
00047 # define MAXCNAMEDEPTH      3
00048 #endif /* USE_ARLIB */
00049 
00050 /* opendkim includes */
00051 #include "opendkim-dns.h"
00052 #include "opendkim-db.h"
00053 #include "util.h"
00054 
00055 /* macros */
00056 #ifndef FALSE
00057 # define FALSE       0
00058 #endif /* ! FALSE */
00059 #ifndef TRUE
00060 # define TRUE 1
00061 #endif /* ! TRUE */
00062 #ifndef MIN
00063 # define MIN(x,y)    ((x) < (y) ? (x) : (y))
00064 #endif /* ! MIN */
00065 
00066 #define       BUFRSZ               1024
00067 #define       MAXPACKET            8192
00068 
00069 /* struct dkimf_fquery -- a file-based DNS query */
00070 struct dkimf_fquery
00071 {
00072        unsigned char *             fq_rbuf;
00073        size_t               fq_rbuflen;
00074        size_t               fq_qlen;
00075        unsigned char        fq_qbuf[MAXPACKET];
00076 };
00077 
00078 #ifdef USE_UNBOUND
00079 /* struct dkimf_unbound -- unbound context */
00080 struct dkimf_unbound
00081 {
00082        _Bool                ub_poller;
00083        struct ub_ctx *             ub_ub;
00084        pthread_mutex_t             ub_lock;
00085        pthread_cond_t              ub_ready;
00086 };
00087 
00088 /* struct dkimf_unbound_cb_data -- libunbound callback data */
00089 struct dkimf_unbound_cb_data
00090 {
00091        int                  ubd_done;
00092        int                  ubd_rcode;
00093        int                  ubd_id;
00094        int                  ubd_type;
00095        int                  ubd_result;
00096        DKIM_STAT            ubd_stat;
00097        size_t               ubd_buflen;
00098        u_char *             ubd_buf;
00099        const char *         ubd_strerror;
00100 };
00101 
00102 /*
00103 **  DKIMF_UNBOUND_CB -- callback to handle result of DNS query
00104 **
00105 **  Parameters:
00106 **     mydata -- structure to return data to DKIM_GET_KEY_DNS
00107 **     err -- error code from unbound resolver
00108 **     result -- result of DNS query
00109 **
00110 **  Return value:
00111 **     None.
00112 */
00113 
00114 static void
00115 dkimf_unbound_cb(void *mydata, int err, struct ub_result *result)
00116 {
00117        struct dkimf_unbound_cb_data *ubdata;
00118 
00119        ubdata = (struct dkimf_unbound_cb_data *) mydata;
00120 
00121        if (err != 0)
00122        {
00123               ubdata->ubd_done = TRUE;
00124               ubdata->ubd_stat = DKIM_STAT_INTERNAL;
00125               ubdata->ubd_strerror = ub_strerror(err);
00126               return;
00127        }
00128 
00129        ubdata->ubd_done = FALSE;
00130        ubdata->ubd_stat = DKIM_STAT_NOKEY;
00131        ubdata->ubd_rcode = result->rcode;
00132        memcpy(ubdata->ubd_buf, result->answer_packet,
00133               MIN(ubdata->ubd_buflen, result->answer_len));
00134        ubdata->ubd_buflen = result->answer_len;
00135 
00136        /*
00137        **  Check whether reply is either secure or insecure.  If bogus,
00138        **  treat as if no key exists.
00139        */
00140 
00141        if (result->secure)
00142        {
00143               ubdata->ubd_result = DKIM_DNSSEC_SECURE;
00144        }
00145        else if (result->bogus)
00146        {
00147               /* result was bogus */
00148               ubdata->ubd_result = DKIM_DNSSEC_BOGUS;
00149               return;
00150        }
00151        else
00152        { 
00153               ubdata->ubd_result = DKIM_DNSSEC_INSECURE;
00154        }
00155 
00156        if (result->havedata && !result->nxdomain && result->rcode == NOERROR)
00157               ubdata->ubd_stat = DKIM_STAT_OK;
00158 
00159        ub_resolve_free(result);
00160 
00161        ubdata->ubd_done = TRUE;
00162 }
00163 
00164 /*
00165 **  DKIMF_UNBOUND_WAIT -- wait for a reply from libunbound
00166 **
00167 **  Parameters:
00168 **     ub -- unbound handle
00169 **     ubdata -- pointer to a struct dkimf_unbound_cb_data
00170 **     to -- timeout (or NULL)
00171 **
00172 **  Return value:
00173 **     1 -- success
00174 **     0 -- timeout
00175 **     -1 -- error
00176 */
00177 
00178 static int
00179 dkimf_unbound_wait(struct dkimf_unbound *ub,
00180                    struct dkimf_unbound_cb_data *ubdata,
00181                    struct timeval *to)
00182 {
00183        struct timespec timeout;
00184        struct timeval now;
00185 
00186        assert(ub != NULL);
00187        assert(ubdata != NULL);
00188 
00189        if (to != NULL)
00190        {
00191               (void) gettimeofday(&now, NULL);
00192 
00193               timeout.tv_sec = now.tv_sec + to->tv_sec;
00194               timeout.tv_nsec = now.tv_usec * 1000;
00195               timeout.tv_nsec += (1000 * to->tv_usec);
00196               if (timeout.tv_nsec > 1000000000)
00197               {
00198                      timeout.tv_sec += (timeout.tv_nsec / 1000000000);
00199                      timeout.tv_nsec = timeout.tv_nsec % 1000000000;
00200               }
00201        }
00202 
00203        pthread_mutex_lock(&ub->ub_lock);
00204 
00205        for (;;)
00206        {
00207               /*
00208               **  Wait for a signal unless/until:
00209               **     a) our request is done
00210               **     b) there's nobody polling libunbound for results
00211               **     c) we don't want to wait anymore (timeout)
00212               */
00213 
00214               if (to != NULL)
00215               {
00216                      while (!ubdata->ubd_done && ub->ub_poller &&
00217                             !dkimf_timespec_past(&timeout))
00218                      {
00219                             (void) pthread_cond_timedwait(&ub->ub_ready,
00220                                                           &ub->ub_lock,
00221                                                           &timeout);
00222                      }
00223               }
00224               else
00225               {
00226                      while (!ubdata->ubd_done && ub->ub_poller)
00227                      {
00228                             (void) pthread_cond_wait(&ub->ub_ready,
00229                                                      &ub->ub_lock);
00230                      }
00231               }
00232 
00233               if (ubdata->ubd_done)
00234               {
00235                      /* our request completed */
00236                      pthread_mutex_unlock(&ub->ub_lock);
00237                      return 1;
00238               }
00239               else if (to != NULL && dkimf_timespec_past(&timeout))
00240               {
00241                      /* our request timed out */
00242                      pthread_mutex_unlock(&ub->ub_lock);
00243                      return 0;
00244               }
00245               else
00246               {
00247                      int status;
00248 
00249                      /* nobody's waiting for results, so we will */
00250                      ub->ub_poller = TRUE;
00251                      pthread_mutex_unlock(&ub->ub_lock);
00252 
00253                      /* wait for I/O to be available */
00254                      status = dkimf_wait_fd(ub_fd(ub->ub_ub),
00255                                             to == NULL ? NULL : &timeout);
00256 
00257                      if (status == 0)
00258                      {
00259                             /* no answer in time */
00260                             pthread_mutex_lock(&ub->ub_lock);
00261                             ub->ub_poller = FALSE;
00262                             pthread_cond_signal(&ub->ub_ready);
00263                             pthread_mutex_unlock(&ub->ub_lock);
00264                             return 0;
00265                      }
00266 
00267                      assert(status == 1);
00268                      
00269                      /* process anything pending */
00270                      status = ub_process(ub->ub_ub);
00271                      if (status != 0)
00272                      {
00273                             /* error during processing */
00274                             pthread_mutex_lock(&ub->ub_lock);
00275                             ub->ub_poller = FALSE;
00276                             pthread_cond_signal(&ub->ub_ready);
00277                             pthread_mutex_unlock(&ub->ub_lock);
00278                             return -1;
00279                      }
00280 
00281                      /* recover the lock so the loop can restart */
00282                      pthread_mutex_lock(&ub->ub_lock);
00283 
00284                      /* tell everyone to check for results */
00285                      pthread_cond_broadcast(&ub->ub_ready);
00286 
00287                      /* clear the "someone is polling" flag */
00288                      ub->ub_poller = FALSE;
00289               }
00290        }
00291 }
00292 
00293 /*
00294 **  DKIMF_UNBOUND_QUEUE -- queue a request for processing by libunbound
00295 **
00296 **  Parameters:
00297 **     ub -- unbound context
00298 **     name -- name to query
00299 **     type -- record type to request
00300 **     buf -- where to write the result
00301 **     buflen -- bytes available at "buf"
00302 **     cbdata -- callback data structure to use
00303 **
00304 **  Return value:
00305 **     0 -- success
00306 **     -1 -- error
00307 */
00308 
00309 static int
00310 dkimf_unbound_queue(struct dkimf_unbound *ub, char *name, int type,
00311                     u_char *buf, size_t buflen,
00312                     struct dkimf_unbound_cb_data *cbdata)
00313 {
00314        int status;
00315 
00316        assert(ub != NULL);
00317        assert(name != NULL);
00318        assert(buf != NULL);
00319        assert(buflen > 0);
00320        assert(cbdata != NULL);
00321 
00322        cbdata->ubd_done = FALSE;
00323        cbdata->ubd_buf = buf;
00324        cbdata->ubd_buflen = buflen;
00325        cbdata->ubd_stat = DKIM_STAT_OK;
00326        cbdata->ubd_result = DKIM_DNSSEC_UNKNOWN;
00327        cbdata->ubd_rcode = NOERROR;
00328        cbdata->ubd_type = type;
00329 
00330        status = ub_resolve_async(ub->ub_ub, name, type, C_IN,
00331                                  (void *) cbdata, dkimf_unbound_cb,
00332                                  &cbdata->ubd_id);
00333        if (status != 0)
00334               return -1;
00335 
00336        return 0;
00337 }
00338 
00339 /*
00340 **  DKIMF_UB_CANCEL -- function passed to libopendkim to handle cancel requests
00341 **
00342 **  Parameters:
00343 **     srv -- service handle
00344 **     q -- query handle
00345 **
00346 **  Return value:
00347 **     A DKIM_DNS_* constant.
00348 */
00349 
00350 static int
00351 dkimf_ub_cancel(void *srv, void *q)
00352 {
00353        struct dkimf_unbound *ub;
00354        struct dkimf_unbound_cb_data *ubdata;
00355 
00356        assert(srv != NULL);
00357        assert(q != NULL);
00358 
00359        ub = (struct dkimf_unbound *) srv;
00360        ubdata = (struct dkimf_unbound_cb_data *) q;
00361 
00362        (void) ub_cancel(ub->ub_ub, ubdata->ubd_id);
00363 
00364        free(q);
00365 
00366        return DKIM_DNS_SUCCESS;
00367 }
00368 
00369 /*
00370 **  DKIMF_UB_QUERY -- function passed to libopendkim to handle new requests
00371 **
00372 **  Parameters:
00373 **     srv -- service handle
00374 **
00375 **  Return value:
00376 **     A DKIM_DNS_* constant.
00377 */
00378 
00379 static int
00380 dkimf_ub_query(void *srv, int type, unsigned char *query,
00381                unsigned char *buf, size_t buflen, void **qh)
00382 {
00383        int status;
00384        struct dkimf_unbound *ub;
00385        struct dkimf_unbound_cb_data *ubdata;
00386 
00387        assert(srv != NULL);
00388        assert(query != NULL);
00389        assert(buf != NULL);
00390        assert(qh != NULL);
00391 
00392        ub = (struct dkimf_unbound *) srv;
00393 
00394        ubdata = (struct dkimf_unbound_cb_data *) malloc(sizeof *ubdata);
00395        if (ubdata == NULL)
00396               return DKIM_DNS_ERROR;
00397        memset(ubdata, '\0', sizeof *ubdata);
00398 
00399        status = dkimf_unbound_queue(ub, (char *) query, type, buf, buflen,
00400                                     ubdata);
00401        if (status != 0)
00402        {
00403               free(ubdata);
00404               return DKIM_DNS_ERROR;
00405        }
00406 
00407        *qh = ubdata;
00408 
00409        return DKIM_DNS_SUCCESS;
00410 }
00411 
00412 /*
00413 **  DKIMF_UB_WAITREPLY -- function passed to libopendkim to handle
00414 **                        wait requests
00415 **
00416 **  Parameters:
00417 **     srv -- service handle
00418 **     q -- query handle
00419 **     to -- wait timeout
00420 **     bytes -- bytes (returned)
00421 **     error -- error code (returned)
00422 **     dnssec -- DNSSEC status (returned)
00423 **
00424 **  Return value:
00425 **     A DKIM_DNS_* constant.
00426 */
00427 
00428 static int
00429 dkimf_ub_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00430                    int *error, int *dnssec)
00431 {
00432        int status;
00433        struct dkimf_unbound *ub;
00434        struct dkimf_unbound_cb_data *ubdata;
00435 
00436        assert(srv != NULL);
00437        assert(qh != NULL);
00438 
00439        ub = (struct dkimf_unbound *) srv;
00440        ubdata = (struct dkimf_unbound_cb_data *) qh;
00441 
00442        status = dkimf_unbound_wait(ub, ubdata, to);
00443        if (status == 1 || status == -1)
00444        {
00445               if (dnssec != NULL)
00446                      *dnssec = ubdata->ubd_result;
00447               if (bytes != NULL)
00448                      *bytes = ubdata->ubd_buflen;
00449               if (error != NULL && status == -1)
00450                      *error = status;     /* XXX -- improve this */
00451        }
00452 
00453        if (status == 0)
00454               return DKIM_DNS_EXPIRED;
00455        else if (status == 1)
00456               return DKIM_DNS_SUCCESS;
00457        else
00458               return DKIM_DNS_ERROR;
00459 }
00460 
00461 /* =========================== PUBLIC FUNCTIONS =========================== */
00462 
00463 /*
00464 **  DKIMF_UNBOUND_INIT -- set up a libunbound context and other data
00465 **
00466 **  Parameters:
00467 **     ub -- unbound context (returned)
00468 **
00469 **  Return value:
00470 **     0 -- success
00471 **     -1 -- failure
00472 */
00473 
00474 int
00475 dkimf_unbound_init(struct dkimf_unbound **ub)
00476 {
00477        struct dkimf_unbound *out;
00478 
00479        assert(ub != NULL);
00480 
00481        out = (struct dkimf_unbound *) malloc(sizeof *out);
00482        if (out == NULL)
00483               return -1;
00484 
00485        out->ub_ub = ub_ctx_create();
00486        if (out->ub_ub == NULL)
00487        {
00488               free(out);
00489               return -1;
00490        }
00491 
00492        /* suppress debug output */
00493        (void) ub_ctx_debugout(out->ub_ub, NULL);
00494 
00495        /* set for asynchronous operation */
00496        ub_ctx_async(out->ub_ub, TRUE);
00497 
00498        out->ub_poller = FALSE;
00499 
00500        pthread_mutex_init(&out->ub_lock, NULL);
00501        pthread_cond_init(&out->ub_ready, NULL);
00502 
00503        *ub = out;
00504 
00505        return 0;
00506 }
00507 
00508 /*
00509 **  DKIMF_UNBOUND_CLOSE -- shut down a libunbound context
00510 **
00511 **  Parameters:
00512 **     ub -- unbound context
00513 **
00514 **  Return value:
00515 **     0 -- success
00516 **     -1 -- failure
00517 */
00518 
00519 int
00520 dkimf_unbound_close(struct dkimf_unbound *ub)
00521 {
00522        assert(ub != NULL);
00523 
00524        ub_ctx_delete(ub->ub_ub);
00525        pthread_mutex_destroy(&ub->ub_lock);
00526        pthread_cond_destroy(&ub->ub_ready);
00527 
00528        return 0;
00529 }
00530 
00531 # ifdef _FFR_RBL
00532 /*
00533 **  DKIMF_RBL_UNBOUND_SETUP -- connect libunbound to librbl
00534 **
00535 **  Parameters:
00536 **     rbl -- librbl handle
00537 **     ub -- dkimf_unbound handle to use
00538 **
00539 **  Return value:
00540 **     0 on success, -1 on failure
00541 */
00542 
00543 int
00544 dkimf_rbl_unbound_setup(RBL *rbl, struct dkimf_unbound *ub)
00545 {
00546        assert(rbl != NULL);
00547        assert(ub != NULL);
00548 
00549        (void) rbl_dns_set_query_service(rbl, ub);
00550        (void) rbl_dns_set_query_start(rbl, dkimf_ub_query);
00551        (void) rbl_dns_set_query_cancel(rbl, dkimf_ub_cancel);
00552        (void) rbl_dns_set_query_waitreply(rbl, dkimf_ub_waitreply);
00553 
00554        return 0;
00555 }
00556 # endif /* _FFR_RBL */
00557 
00558 # ifdef _FFR_DKIM_REPUTATION
00559 /*
00560 **  DKIMF_RBL_UNBOUND_SETUP -- connect libunbound to librbl
00561 **
00562 **  Parameters:
00563 **     dr -- DKIM_REP handle
00564 **     ub -- dkimf_unbound handle to use
00565 **
00566 **  Return value:
00567 **     0 on success, -1 on failure
00568 */
00569 
00570 int
00571 dkimf_rep_unbound_setup(DKIM_REP dr, struct dkimf_unbound *ub)
00572 {
00573        assert(dr != NULL);
00574        assert(ub != NULL);
00575 
00576        (void) dkim_rep_dns_set_query_service(dr, ub);
00577        (void) dkim_rep_dns_set_query_start(dr, dkimf_ub_query);
00578        (void) dkim_rep_dns_set_query_cancel(dr, dkimf_ub_cancel);
00579        (void) dkim_rep_dns_set_query_waitreply(dr, dkimf_ub_waitreply);
00580 
00581        return 0;
00582 }
00583 # endif /* _FFR_DKIM_REPUTATION */
00584 
00585 /*
00586 **  DKIMF_UNBOUND_SETUP -- connect libunbound to libopendkim
00587 **
00588 **  Parameters:
00589 **     lib -- libopendkim handle
00590 **     ub -- dkimf_unbound handle to use
00591 **
00592 **  Return value:
00593 **     0 on success, -1 on failure
00594 */
00595 
00596 int
00597 dkimf_unbound_setup(DKIM_LIB *lib, struct dkimf_unbound *ub)
00598 {
00599        assert(lib != NULL);
00600        assert(ub != NULL);
00601 
00602        (void) dkim_dns_set_query_service(lib, ub);
00603        (void) dkim_dns_set_query_start(lib, dkimf_ub_query);
00604        (void) dkim_dns_set_query_cancel(lib, dkimf_ub_cancel);
00605        (void) dkim_dns_set_query_waitreply(lib, dkimf_ub_waitreply);
00606 
00607        return 0;
00608 }
00609 
00610 /*
00611 **  DKIMF_UNBOUND_ADD_TRUSTANCHOR -- add a trust anchor file to a
00612 **                                   libunbound context
00613 **
00614 **  Parameters:
00615 **     ub -- libunbound context
00616 **     file -- path to add
00617 **
00618 **  Return value:
00619 **     0 -- success
00620 **     -1 -- error
00621 */
00622 
00623 int
00624 dkimf_unbound_add_trustanchor(struct dkimf_unbound *ub, char *file)
00625 {
00626        int status;
00627 
00628        assert(ub != NULL);
00629        assert(file != NULL);
00630        status = ub_ctx_add_ta_file(ub->ub_ub, file);
00631 
00632        return (status == 0 ? 0 : -1);
00633 }
00634 
00635 /*
00636 **  DKIMF_UNBOUND_ADD_CONFFILE -- add a configuration file to a libunbound
00637 **                                context
00638 **
00639 **  Parameters:
00640 **     ub -- libunbound context
00641 **     file -- path to add
00642 **
00643 **  Return value:
00644 **     0 -- success
00645 **     -1 -- error
00646 */
00647 
00648 int
00649 dkimf_unbound_add_conffile(struct dkimf_unbound *ub, char *file)
00650 {
00651        int status;
00652 
00653        assert(ub != NULL);
00654        assert(file != NULL);
00655 
00656        status = ub_ctx_config(ub->ub_ub, file);
00657 
00658        return (status == 0 ? 0 : -1);
00659 }
00660 #endif /* USE_UNBOUND */
00661 
00662 #ifdef USE_ARLIB
00663 /*
00664 **  DKIMF_AR_CANCEL -- function passed to libopendkim to handle cancel
00665 **                     requests
00666 **
00667 **  Parameters:
00668 **     srv -- service handle
00669 **     q -- query handle
00670 **
00671 **  Return value:
00672 **     A DKIM_DNS_* constant.
00673 */
00674 
00675 static int
00676 dkimf_ar_cancel(void *srv, void *q)
00677 {
00678        AR_LIB ar;
00679        AR_QUERY arq;
00680 
00681        assert(srv != NULL);
00682        assert(q != NULL);
00683 
00684        ar = (AR_LIB) srv;
00685        arq = (AR_QUERY) q;
00686 
00687        (void) ar_cancelquery(ar, arq);
00688 
00689        return DKIM_DNS_SUCCESS;
00690 }
00691 
00692 /*
00693 **  DKIMF_AR_QUERY -- function passed to libopendkim to handle new requests
00694 **
00695 **  Parameters:
00696 **     srv -- service handle
00697 **
00698 **  Return value:
00699 **     A DKIM_DNS_* constant.
00700 */
00701 
00702 static int
00703 dkimf_ar_query(void *srv, int type, unsigned char *query,
00704                unsigned char *buf, size_t buflen, void **qh)
00705 {
00706        AR_LIB ar;
00707        AR_QUERY q;
00708 
00709        assert(srv != NULL);
00710        assert(query != NULL);
00711        assert(buf != NULL);
00712        assert(qh != NULL);
00713 
00714        ar = (AR_LIB) srv;
00715 
00716        q = ar_addquery(ar, (char *) query, C_IN, type, MAXCNAMEDEPTH,
00717                        buf, buflen, (int *) NULL, (struct timeval *) NULL);
00718        if (q == NULL)
00719               return DKIM_DNS_ERROR;
00720 
00721        *qh = (void *) q;
00722 
00723        return DKIM_DNS_SUCCESS;
00724 }
00725 
00726 /*
00727 **  DKIMF_AR_WAITREPLY -- function passed to libopendkim to handle
00728 **                        wait requests
00729 **
00730 **  Parameters:
00731 **     srv -- service handle
00732 **     q -- query handle
00733 **     to -- wait timeout
00734 **     bytes -- bytes (returned)
00735 **     error -- error code (returned)
00736 **     dnssec -- DNSSEC status (returned)
00737 **
00738 **  Return value:
00739 **     A DKIM_DNS_* constant.
00740 */
00741 
00742 static int
00743 dkimf_ar_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00744                    int *error, int *dnssec)
00745 {
00746        int status;
00747        size_t r;
00748        AR_LIB ar;
00749        AR_QUERY q;
00750 
00751        assert(srv != NULL);
00752        assert(qh != NULL);
00753 
00754        ar = (AR_LIB) srv;
00755        q = (AR_QUERY) qh;
00756 
00757        status = ar_waitreply(ar, q, &r, to);
00758        if (status == AR_STAT_SUCCESS)
00759        {
00760               if (dnssec != NULL)
00761                      *dnssec = DKIM_DNSSEC_UNKNOWN;
00762               if (bytes != NULL)
00763                      *bytes = r;
00764        }
00765        else
00766        {
00767               if (error != NULL)
00768                      *error = errno;
00769        }
00770 
00771        if (status == AR_STAT_SUCCESS)
00772               return DKIM_DNS_SUCCESS;
00773        else if (status == AR_STAT_NOREPLY)
00774               return DKIM_DNS_EXPIRED;
00775        else
00776               return DKIM_DNS_ERROR;
00777 }
00778 
00779 /* =========================== PUBLIC FUNCTIONS =========================== */
00780 
00781 # ifdef _FFR_RBL
00782 /*
00783 **  DKIMF_RBL_ARLIB_SETUP -- connect libar to librbl
00784 **
00785 **  Parameters:
00786 **     rbl -- librbl handle
00787 **     libar -- AR_LIB handle
00788 **
00789 **  Return value:
00790 **     0 on success, -1 on failure
00791 */
00792 
00793 int
00794 dkimf_rbl_arlib_setup(RBL *rbl, AR_LIB ar)
00795 {
00796        assert(rbl != NULL);
00797        assert(ar != NULL);
00798 
00799        (void) rbl_dns_set_query_service(rbl, ar);
00800        (void) rbl_dns_set_query_start(rbl, dkimf_ar_query);
00801        (void) rbl_dns_set_query_cancel(rbl, dkimf_ar_cancel);
00802        (void) rbl_dns_set_query_waitreply(rbl, dkimf_ar_waitreply);
00803 
00804        return 0;
00805 }
00806 # endif /* _FFR_RBL */
00807 
00808 # ifdef _FFR_DKIM_REPUTATION
00809 /*
00810 **  DKIMF_REP_ARLIB_SETUP -- connect libar to libdkimrep
00811 **
00812 **  Parameters:
00813 **     dr -- DKIM_REP handle
00814 **     libar -- AR_LIB handle
00815 **
00816 **  Return value:
00817 **     0 on success, -1 on failure
00818 */
00819 
00820 int
00821 dkimf_rep_arlib_setup(DKIM_REP dr, AR_LIB ar)
00822 {
00823        assert(dr != NULL);
00824        assert(ar != NULL);
00825 
00826        (void) dkim_rep_dns_set_query_service(dr, ar);
00827        (void) dkim_rep_dns_set_query_start(dr, dkimf_ar_query);
00828        (void) dkim_rep_dns_set_query_cancel(dr, dkimf_ar_cancel);
00829        (void) dkim_rep_dns_set_query_waitreply(dr, dkimf_ar_waitreply);
00830 
00831        return 0;
00832 }
00833 # endif /* _FFR_DKIM_REPUTATION */
00834 
00835 /*
00836 **  DKIMF_ARLIB_SETUP -- connect libar to libopendkim
00837 **
00838 **  Parameters:
00839 **     lib -- libopendkim handle
00840 **     libar -- AR_LIB handle
00841 **
00842 **  Return value:
00843 **     0 on success, -1 on failure
00844 */
00845 
00846 int
00847 dkimf_arlib_setup(DKIM_LIB *lib, AR_LIB ar)
00848 {
00849        assert(lib != NULL);
00850        assert(ar != NULL);
00851 
00852        (void) dkim_dns_set_query_service(lib, ar);
00853        (void) dkim_dns_set_query_start(lib, dkimf_ar_query);
00854        (void) dkim_dns_set_query_cancel(lib, dkimf_ar_cancel);
00855        (void) dkim_dns_set_query_waitreply(lib, dkimf_ar_waitreply);
00856 
00857        return 0;
00858 }
00859 #endif /* USE_ARLIB */
00860 
00861 /*
00862 **  DKIMF_FILEDNS_QUERY -- function passed to libopendkim to handle new
00863 **                         requests
00864 **
00865 **  Parameters:
00866 **     srv -- service handle
00867 **
00868 **  Return value:
00869 **     A DKIM_DNS_* constant.
00870 */
00871 
00872 static int
00873 dkimf_filedns_query(void *srv, int type, unsigned char *query,
00874                     unsigned char *buf, size_t buflen, void **qh)
00875 {
00876        int status;
00877        struct dkimf_fquery *fq;
00878        size_t qlen;
00879 
00880        assert(srv != NULL);
00881        assert(query != NULL);
00882        assert(buf != NULL);
00883        assert(qh != NULL);
00884 
00885        if (type != T_TXT)
00886               return DKIM_DNS_SUCCESS;
00887 
00888        fq = malloc(sizeof *fq);
00889        if (fq == NULL)
00890               return DKIM_DNS_ERROR;
00891        fq->fq_rbuf = buf;
00892        fq->fq_rbuflen = buflen;
00893 
00894        qlen = res_mkquery(QUERY, query, C_IN, type, NULL, 0, NULL,
00895                           fq->fq_qbuf, sizeof fq->fq_qbuf);
00896        if (qlen == (size_t) -1)
00897        {
00898               free(fq);
00899               return DKIM_DNS_ERROR;
00900        }
00901 
00902        fq->fq_qlen = qlen;
00903 
00904        *qh = fq;
00905 
00906        return DKIM_DNS_SUCCESS;
00907 }
00908 
00909 /*
00910 **  DKIMF_FILEDNS_CANCEL -- function passed to libopendkim to handle cancel
00911 **                          requests
00912 **
00913 **  Parameters:
00914 **     srv -- service handle
00915 **     q -- query handle
00916 **
00917 **  Return value:
00918 **     A DKIM_DNS_* constant.
00919 */
00920 
00921 static int
00922 dkimf_filedns_cancel(void *srv, void *q)
00923 {
00924        struct dkimf_fquery *fq;
00925 
00926        assert(srv != NULL);
00927        assert(q != NULL);
00928 
00929        fq = q;
00930 
00931        free(fq);
00932 
00933        return DKIM_DNS_SUCCESS;
00934 }
00935 
00936 /*
00937 **  DKIMF_FILEDNS_WAITREPLY -- function passed to libopendkim to handle
00938 **                             wait requests
00939 **
00940 **  Parameters:
00941 **     srv -- service handle
00942 **     q -- query handle
00943 **     to -- wait timeout
00944 **     bytes -- bytes (returned)
00945 **     error -- error code (returned)
00946 **     dnssec -- DNSSEC status (returned)
00947 **
00948 **  Return value:
00949 **     A DKIM_DNS_* constant.
00950 */
00951 
00952 static int
00953 dkimf_filedns_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00954                         int *error, int *dnssec)
00955 {
00956        _Bool exists = FALSE;
00957        int n;
00958        int status;
00959        int qdcount;
00960        char *cp;
00961        char *eom;
00962        char *qstart;
00963        struct dkimf_fquery *fq;
00964        char qname[BUFRSZ + 1];
00965        char buf[BUFRSZ + 1];
00966        HEADER hdr;
00967        struct dkimf_db_data dbd;
00968 
00969        assert(srv != NULL);
00970        assert(qh != NULL);
00971 
00972        fq = (struct dkimf_fquery *) qh;
00973 
00974        /* recover the query */
00975        qstart = fq->fq_rbuf;
00976        cp = fq->fq_qbuf;
00977        eom = cp + sizeof fq->fq_qbuf;
00978        memcpy(&hdr, cp, sizeof hdr);
00979        cp += HFIXEDSZ;
00980 
00981        /* skip over the name at the front of the answer */
00982        memset(qname, '\0', sizeof qname);
00983        for (qdcount = ntohs((unsigned short) hdr.qdcount);
00984             qdcount > 0;
00985             qdcount--)
00986        {
00987               /* copy it first */
00988               (void) dn_expand((unsigned char *) fq->fq_qbuf, eom, cp,
00989                                (char *) qname, sizeof qname);
00990  
00991               if ((n = dn_skipname(cp, eom)) < 0)
00992                      return DKIM_DNS_ERROR;;
00993 
00994               cp += n;
00995 
00996               /* extract the type and class */
00997               if (cp + INT16SZ + INT16SZ > eom)
00998                      return DKIM_DNS_ERROR;
00999 ;
01000               cp += (INT16SZ + INT16SZ);
01001        }
01002 
01003        /* search the DB */
01004        dbd.dbdata_buffer = buf;
01005        dbd.dbdata_buflen = sizeof buf;
01006        dbd.dbdata_flags = 0;
01007 
01008        memset(buf, '\0', sizeof buf);
01009 
01010        /* see if it's in the DB */
01011        status = dkimf_db_get((DKIMF_DB) srv, qname, strlen(qname), &dbd, 1,
01012                              &exists);
01013        if (status != 0)
01014               return DKIM_DNS_ERROR;
01015 
01016        /* prepare a reply header */
01017        hdr.qr = 1;
01018 
01019        if (!exists)
01020        {                    /* not found; set up an NXDOMAIN reply */
01021               hdr.rcode = NXDOMAIN;
01022               hdr.ancount = htons(0);
01023 
01024               memcpy(fq->fq_qbuf, &hdr, sizeof hdr);
01025 
01026               *bytes = fq->fq_qlen;
01027        }
01028        else
01029        {                    /* found, construct the reply */
01030               int elen;
01031               int slen;
01032               int olen;
01033               char *q;
01034               unsigned char *len;
01035               unsigned char *dnptrs[3];
01036               unsigned char **lastdnptr;
01037               HEADER newhdr;
01038 
01039               lastdnptr = &dnptrs[2];
01040 
01041               memset(&newhdr, '\0', sizeof newhdr);
01042               memset(&dnptrs, '\0', sizeof dnptrs);
01043               
01044               newhdr.qdcount = htons(1);
01045               newhdr.ancount = htons(1);
01046               newhdr.rcode = NOERROR;
01047               newhdr.opcode = hdr.opcode;
01048               newhdr.qr = 1;
01049               newhdr.id = hdr.id;
01050 
01051               dnptrs[0] = fq->fq_qbuf;
01052 
01053               /* copy out the new header */
01054               memcpy(fq->fq_rbuf, &newhdr, sizeof newhdr);
01055 
01056               cp = fq->fq_rbuf + HFIXEDSZ;
01057               eom = fq->fq_rbuf + fq->fq_rbuflen;
01058 
01059               /* question section */
01060               elen = dn_comp(qname, cp, eom - cp, dnptrs, lastdnptr);
01061               if (elen == -1)
01062                      return DKIM_DNS_ERROR;
01063               cp += elen;
01064               PUTSHORT(T_TXT, cp);
01065               PUTSHORT(C_IN, cp);
01066 
01067               /* answer section */
01068               elen = dn_comp(qname, cp, eom - cp, dnptrs, lastdnptr);
01069               if (elen == -1)
01070                      return DKIM_DNS_ERROR;
01071               cp += elen;
01072               PUTSHORT(T_TXT, cp);
01073               PUTSHORT(C_IN, cp);
01074               PUTLONG(0L, cp);
01075 
01076               len = cp;
01077               cp += INT16SZ;
01078 
01079               slen = dbd.dbdata_buflen;
01080               olen = 0;
01081               q = buf;
01082 
01083               while (slen > 0)
01084               {
01085                      elen = MIN(slen, 255);
01086                      *cp = (char) elen;
01087                      cp++;
01088                      olen++;
01089                      memcpy(cp, q, elen);
01090                      q += elen;
01091                      cp += elen;
01092                      olen += elen;
01093                      slen -= elen;
01094               }
01095 
01096               eom = cp;
01097 
01098               cp = len;
01099               PUTSHORT(olen, cp);
01100 
01101               *bytes = eom - qstart;
01102        }
01103 
01104        if (dnssec != NULL)
01105               *dnssec = DKIM_DNSSEC_UNKNOWN;
01106 
01107        return DKIM_DNS_SUCCESS;
01108 }
01109 
01110 /*
01111 **  DKIMF_FILEDNS_SETUP -- connect a file DNS to libopendkim
01112 **
01113 **  Parameters:
01114 **     lib -- libopendkim handle
01115 **     db -- data set from which to read
01116 **
01117 **  Return value:
01118 **     0 on success, -1 on failure
01119 */
01120 
01121 int
01122 dkimf_filedns_setup(DKIM_LIB *lib, DKIMF_DB db)
01123 {
01124        assert(lib != NULL);
01125        assert(db != NULL);
01126 
01127        (void) dkim_dns_set_query_service(lib, db);
01128        (void) dkim_dns_set_query_start(lib, dkimf_filedns_query);
01129        (void) dkim_dns_set_query_cancel(lib, dkimf_filedns_cancel);
01130        (void) dkim_dns_set_query_waitreply(lib, dkimf_filedns_waitreply);
01131 
01132        return 0;
01133 }