Back to index

opendkim  2.6.6
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 
00661 /*
00662 **  DKIMF_UNBOUND_ADD_RESOLVCONF -- tell libunbound to read a resolv.conf file
00663 **
00664 **  Parameters:
00665 **     ub -- libunbound context
00666 **     file -- path to read
00667 **
00668 **  Return value:
00669 **     0 -- success
00670 **     -1 -- error
00671 */
00672 
00673 int
00674 dkimf_unbound_add_resolvconf(struct dkimf_unbound *ub, char *file)
00675 {
00676        int status;
00677 
00678        assert(ub != NULL);
00679        assert(file != NULL);
00680 
00681        status = ub_ctx_resolvconf(ub->ub_ub, file);
00682 
00683        return (status == 0 ? 0 : -1);
00684 }
00685 #endif /* USE_UNBOUND */
00686 
00687 #ifdef USE_ARLIB
00688 /*
00689 **  DKIMF_AR_CANCEL -- function passed to libopendkim to handle cancel
00690 **                     requests
00691 **
00692 **  Parameters:
00693 **     srv -- service handle
00694 **     q -- query handle
00695 **
00696 **  Return value:
00697 **     A DKIM_DNS_* constant.
00698 */
00699 
00700 static int
00701 dkimf_ar_cancel(void *srv, void *q)
00702 {
00703        AR_LIB ar;
00704        AR_QUERY arq;
00705 
00706        assert(srv != NULL);
00707        assert(q != NULL);
00708 
00709        ar = (AR_LIB) srv;
00710        arq = (AR_QUERY) q;
00711 
00712        (void) ar_cancelquery(ar, arq);
00713 
00714        return DKIM_DNS_SUCCESS;
00715 }
00716 
00717 /*
00718 **  DKIMF_AR_QUERY -- function passed to libopendkim to handle new requests
00719 **
00720 **  Parameters:
00721 **     srv -- service handle
00722 **
00723 **  Return value:
00724 **     A DKIM_DNS_* constant.
00725 */
00726 
00727 static int
00728 dkimf_ar_query(void *srv, int type, unsigned char *query,
00729                unsigned char *buf, size_t buflen, void **qh)
00730 {
00731        AR_LIB ar;
00732        AR_QUERY q;
00733 
00734        assert(srv != NULL);
00735        assert(query != NULL);
00736        assert(buf != NULL);
00737        assert(qh != NULL);
00738 
00739        ar = (AR_LIB) srv;
00740 
00741        q = ar_addquery(ar, (char *) query, C_IN, type, MAXCNAMEDEPTH,
00742                        buf, buflen, (int *) NULL, (struct timeval *) NULL);
00743        if (q == NULL)
00744               return DKIM_DNS_ERROR;
00745 
00746        *qh = (void *) q;
00747 
00748        return DKIM_DNS_SUCCESS;
00749 }
00750 
00751 /*
00752 **  DKIMF_AR_WAITREPLY -- function passed to libopendkim to handle
00753 **                        wait requests
00754 **
00755 **  Parameters:
00756 **     srv -- service handle
00757 **     q -- query handle
00758 **     to -- wait timeout
00759 **     bytes -- bytes (returned)
00760 **     error -- error code (returned)
00761 **     dnssec -- DNSSEC status (returned)
00762 **
00763 **  Return value:
00764 **     A DKIM_DNS_* constant.
00765 */
00766 
00767 static int
00768 dkimf_ar_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00769                    int *error, int *dnssec)
00770 {
00771        int status;
00772        size_t r;
00773        AR_LIB ar;
00774        AR_QUERY q;
00775 
00776        assert(srv != NULL);
00777        assert(qh != NULL);
00778 
00779        ar = (AR_LIB) srv;
00780        q = (AR_QUERY) qh;
00781 
00782        status = ar_waitreply(ar, q, &r, to);
00783        if (status == AR_STAT_SUCCESS)
00784        {
00785               if (dnssec != NULL)
00786                      *dnssec = DKIM_DNSSEC_UNKNOWN;
00787               if (bytes != NULL)
00788                      *bytes = r;
00789        }
00790        else
00791        {
00792               if (error != NULL)
00793                      *error = errno;
00794        }
00795 
00796        if (status == AR_STAT_SUCCESS)
00797               return DKIM_DNS_SUCCESS;
00798        else if (status == AR_STAT_NOREPLY)
00799               return DKIM_DNS_EXPIRED;
00800        else
00801               return DKIM_DNS_ERROR;
00802 }
00803 
00804 /* =========================== PUBLIC FUNCTIONS =========================== */
00805 
00806 # ifdef _FFR_RBL
00807 /*
00808 **  DKIMF_RBL_ARLIB_SETUP -- connect libar to librbl
00809 **
00810 **  Parameters:
00811 **     rbl -- librbl handle
00812 **     libar -- AR_LIB handle
00813 **
00814 **  Return value:
00815 **     0 on success, -1 on failure
00816 */
00817 
00818 int
00819 dkimf_rbl_arlib_setup(RBL *rbl, AR_LIB ar)
00820 {
00821        assert(rbl != NULL);
00822        assert(ar != NULL);
00823 
00824        (void) rbl_dns_set_query_service(rbl, ar);
00825        (void) rbl_dns_set_query_start(rbl, dkimf_ar_query);
00826        (void) rbl_dns_set_query_cancel(rbl, dkimf_ar_cancel);
00827        (void) rbl_dns_set_query_waitreply(rbl, dkimf_ar_waitreply);
00828 
00829        return 0;
00830 }
00831 # endif /* _FFR_RBL */
00832 
00833 # ifdef _FFR_DKIM_REPUTATION
00834 /*
00835 **  DKIMF_REP_ARLIB_SETUP -- connect libar to libdkimrep
00836 **
00837 **  Parameters:
00838 **     dr -- DKIM_REP handle
00839 **     libar -- AR_LIB handle
00840 **
00841 **  Return value:
00842 **     0 on success, -1 on failure
00843 */
00844 
00845 int
00846 dkimf_rep_arlib_setup(DKIM_REP dr, AR_LIB ar)
00847 {
00848        assert(dr != NULL);
00849        assert(ar != NULL);
00850 
00851        (void) dkim_rep_dns_set_query_service(dr, ar);
00852        (void) dkim_rep_dns_set_query_start(dr, dkimf_ar_query);
00853        (void) dkim_rep_dns_set_query_cancel(dr, dkimf_ar_cancel);
00854        (void) dkim_rep_dns_set_query_waitreply(dr, dkimf_ar_waitreply);
00855 
00856        return 0;
00857 }
00858 # endif /* _FFR_DKIM_REPUTATION */
00859 
00860 /*
00861 **  DKIMF_ARLIB_SETUP -- connect libar to libopendkim
00862 **
00863 **  Parameters:
00864 **     lib -- libopendkim handle
00865 **     libar -- AR_LIB handle
00866 **
00867 **  Return value:
00868 **     0 on success, -1 on failure
00869 */
00870 
00871 int
00872 dkimf_arlib_setup(DKIM_LIB *lib, AR_LIB ar)
00873 {
00874        assert(lib != NULL);
00875        assert(ar != NULL);
00876 
00877        (void) dkim_dns_set_query_service(lib, ar);
00878        (void) dkim_dns_set_query_start(lib, dkimf_ar_query);
00879        (void) dkim_dns_set_query_cancel(lib, dkimf_ar_cancel);
00880        (void) dkim_dns_set_query_waitreply(lib, dkimf_ar_waitreply);
00881 
00882        return 0;
00883 }
00884 #endif /* USE_ARLIB */
00885 
00886 /*
00887 **  DKIMF_FILEDNS_QUERY -- function passed to libopendkim to handle new
00888 **                         requests
00889 **
00890 **  Parameters:
00891 **     srv -- service handle
00892 **
00893 **  Return value:
00894 **     A DKIM_DNS_* constant.
00895 */
00896 
00897 static int
00898 dkimf_filedns_query(void *srv, int type, unsigned char *query,
00899                     unsigned char *buf, size_t buflen, void **qh)
00900 {
00901        int status;
00902        struct dkimf_fquery *fq;
00903        size_t qlen;
00904 
00905        assert(srv != NULL);
00906        assert(query != NULL);
00907        assert(buf != NULL);
00908        assert(qh != NULL);
00909 
00910        if (type != T_TXT)
00911               return DKIM_DNS_SUCCESS;
00912 
00913        fq = malloc(sizeof *fq);
00914        if (fq == NULL)
00915               return DKIM_DNS_ERROR;
00916        fq->fq_rbuf = buf;
00917        fq->fq_rbuflen = buflen;
00918 
00919        qlen = res_mkquery(QUERY, query, C_IN, type, NULL, 0, NULL,
00920                           fq->fq_qbuf, sizeof fq->fq_qbuf);
00921        if (qlen == (size_t) -1)
00922        {
00923               free(fq);
00924               return DKIM_DNS_ERROR;
00925        }
00926 
00927        fq->fq_qlen = qlen;
00928 
00929        *qh = fq;
00930 
00931        return DKIM_DNS_SUCCESS;
00932 }
00933 
00934 /*
00935 **  DKIMF_FILEDNS_CANCEL -- function passed to libopendkim to handle cancel
00936 **                          requests
00937 **
00938 **  Parameters:
00939 **     srv -- service handle
00940 **     q -- query handle
00941 **
00942 **  Return value:
00943 **     A DKIM_DNS_* constant.
00944 */
00945 
00946 static int
00947 dkimf_filedns_cancel(void *srv, void *q)
00948 {
00949        struct dkimf_fquery *fq;
00950 
00951        assert(srv != NULL);
00952        assert(q != NULL);
00953 
00954        fq = q;
00955 
00956        free(fq);
00957 
00958        return DKIM_DNS_SUCCESS;
00959 }
00960 
00961 /*
00962 **  DKIMF_FILEDNS_WAITREPLY -- function passed to libopendkim to handle
00963 **                             wait requests
00964 **
00965 **  Parameters:
00966 **     srv -- service handle
00967 **     q -- query handle
00968 **     to -- wait timeout
00969 **     bytes -- bytes (returned)
00970 **     error -- error code (returned)
00971 **     dnssec -- DNSSEC status (returned)
00972 **
00973 **  Return value:
00974 **     A DKIM_DNS_* constant.
00975 */
00976 
00977 static int
00978 dkimf_filedns_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00979                         int *error, int *dnssec)
00980 {
00981        _Bool exists = FALSE;
00982        int n;
00983        int status;
00984        int qdcount;
00985        char *cp;
00986        char *eom;
00987        char *qstart;
00988        struct dkimf_fquery *fq;
00989        char qname[BUFRSZ + 1];
00990        char buf[BUFRSZ + 1];
00991        HEADER hdr;
00992        struct dkimf_db_data dbd;
00993 
00994        assert(srv != NULL);
00995        assert(qh != NULL);
00996 
00997        fq = (struct dkimf_fquery *) qh;
00998 
00999        /* recover the query */
01000        qstart = fq->fq_rbuf;
01001        cp = fq->fq_qbuf;
01002        eom = cp + sizeof fq->fq_qbuf;
01003        memcpy(&hdr, cp, sizeof hdr);
01004        cp += HFIXEDSZ;
01005 
01006        /* skip over the name at the front of the answer */
01007        memset(qname, '\0', sizeof qname);
01008        for (qdcount = ntohs((unsigned short) hdr.qdcount);
01009             qdcount > 0;
01010             qdcount--)
01011        {
01012               /* copy it first */
01013               (void) dn_expand((unsigned char *) fq->fq_qbuf, eom, cp,
01014                                (char *) qname, sizeof qname);
01015  
01016               if ((n = dn_skipname(cp, eom)) < 0)
01017                      return DKIM_DNS_ERROR;;
01018 
01019               cp += n;
01020 
01021               /* extract the type and class */
01022               if (cp + INT16SZ + INT16SZ > eom)
01023                      return DKIM_DNS_ERROR;
01024 ;
01025               cp += (INT16SZ + INT16SZ);
01026        }
01027 
01028        /* search the DB */
01029        dbd.dbdata_buffer = buf;
01030        dbd.dbdata_buflen = sizeof buf;
01031        dbd.dbdata_flags = 0;
01032 
01033        memset(buf, '\0', sizeof buf);
01034 
01035        /* see if it's in the DB */
01036        status = dkimf_db_get((DKIMF_DB) srv, qname, strlen(qname), &dbd, 1,
01037                              &exists);
01038        if (status != 0)
01039               return DKIM_DNS_ERROR;
01040 
01041        /* prepare a reply header */
01042        hdr.qr = 1;
01043 
01044        if (!exists)
01045        {                    /* not found; set up an NXDOMAIN reply */
01046               hdr.rcode = NXDOMAIN;
01047               hdr.ancount = htons(0);
01048 
01049               memcpy(fq->fq_qbuf, &hdr, sizeof hdr);
01050 
01051               *bytes = fq->fq_qlen;
01052        }
01053        else
01054        {                    /* found, construct the reply */
01055               int elen;
01056               int slen;
01057               int olen;
01058               char *q;
01059               unsigned char *len;
01060               unsigned char *dnptrs[3];
01061               unsigned char **lastdnptr;
01062               HEADER newhdr;
01063 
01064               lastdnptr = &dnptrs[2];
01065 
01066               memset(&newhdr, '\0', sizeof newhdr);
01067               memset(&dnptrs, '\0', sizeof dnptrs);
01068               
01069               newhdr.qdcount = htons(1);
01070               newhdr.ancount = htons(1);
01071               newhdr.rcode = NOERROR;
01072               newhdr.opcode = hdr.opcode;
01073               newhdr.qr = 1;
01074               newhdr.id = hdr.id;
01075 
01076               dnptrs[0] = fq->fq_qbuf;
01077 
01078               /* copy out the new header */
01079               memcpy(fq->fq_rbuf, &newhdr, sizeof newhdr);
01080 
01081               cp = fq->fq_rbuf + HFIXEDSZ;
01082               eom = fq->fq_rbuf + fq->fq_rbuflen;
01083 
01084               /* question section */
01085               elen = dn_comp(qname, cp, eom - cp, dnptrs, lastdnptr);
01086               if (elen == -1)
01087                      return DKIM_DNS_ERROR;
01088               cp += elen;
01089               PUTSHORT(T_TXT, cp);
01090               PUTSHORT(C_IN, cp);
01091 
01092               /* answer section */
01093               elen = dn_comp(qname, cp, eom - cp, dnptrs, lastdnptr);
01094               if (elen == -1)
01095                      return DKIM_DNS_ERROR;
01096               cp += elen;
01097               PUTSHORT(T_TXT, cp);
01098               PUTSHORT(C_IN, cp);
01099               PUTLONG(0L, cp);
01100 
01101               len = cp;
01102               cp += INT16SZ;
01103 
01104               slen = dbd.dbdata_buflen;
01105               olen = 0;
01106               q = buf;
01107 
01108               while (slen > 0)
01109               {
01110                      elen = MIN(slen, 255);
01111                      *cp = (char) elen;
01112                      cp++;
01113                      olen++;
01114                      memcpy(cp, q, elen);
01115                      q += elen;
01116                      cp += elen;
01117                      olen += elen;
01118                      slen -= elen;
01119               }
01120 
01121               eom = cp;
01122 
01123               cp = len;
01124               PUTSHORT(olen, cp);
01125 
01126               *bytes = eom - qstart;
01127        }
01128 
01129        if (dnssec != NULL)
01130               *dnssec = DKIM_DNSSEC_UNKNOWN;
01131 
01132        return DKIM_DNS_SUCCESS;
01133 }
01134 
01135 /*
01136 **  DKIMF_FILEDNS_SETUP -- connect a file DNS to libopendkim
01137 **
01138 **  Parameters:
01139 **     lib -- libopendkim handle
01140 **     db -- data set from which to read
01141 **
01142 **  Return value:
01143 **     0 on success, -1 on failure
01144 */
01145 
01146 int
01147 dkimf_filedns_setup(DKIM_LIB *lib, DKIMF_DB db)
01148 {
01149        assert(lib != NULL);
01150        assert(db != NULL);
01151 
01152        (void) dkim_dns_set_query_service(lib, db);
01153        (void) dkim_dns_set_query_start(lib, dkimf_filedns_query);
01154        (void) dkim_dns_set_query_cancel(lib, dkimf_filedns_cancel);
01155        (void) dkim_dns_set_query_waitreply(lib, dkimf_filedns_waitreply);
01156 
01157        return 0;
01158 }