Back to index

opendkim  2.6.6
Classes | Defines | Functions | Variables
rbl.c File Reference
#include "build-config.h"
#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "rbl.h"

Go to the source code of this file.

Classes

struct  rbl_query
struct  rbl_handle
struct  rbl_res_qh

Defines

#define MAXPACKET   8192
#define RES_UNC_T   unsigned char *
#define T_RRSIG   46

Functions

static int rbl_res_cancel (void *srv, void *qh)
static int rbl_res_query (void *srv, int type, unsigned char *query, unsigned char *buf, size_t buflen, void **qh)
int rbl_res_waitreply (void *srv, void *qh, struct timeval *to, size_t *bytes, int *error, int *dnssec)
RBL * rbl_init (void *(*caller_mallocf)(void *closure, size_t nbytes), void(*caller_freef)(void *closure, void *p), void *closure)
void rbl_close (RBL *rbl)
const u_char * rbl_geterror (RBL *rbl)
void rbl_setdomain (RBL *rbl, u_char *qroot)
void rbl_settimeout (RBL *rbl, u_int timeout)
void rbl_setcallbackint (RBL *rbl, u_int cbint)
void rbl_setcallbackctx (RBL *rbl, void *ctx)
void rbl_setdnscallback (RBL *rbl, void(*func)(const void *context))
void * rbl_dns_set_query_service (RBL *rbl, void *h)
void rbl_dns_set_query_start (RBL *rbl, int(*func)(void *, int, unsigned char *, unsigned char *, size_t, void **))
void rbl_dns_set_query_cancel (RBL *rbl, int(*func)(void *, void *))
void rbl_dns_set_query_waitreply (RBL *rbl, int(*func)(void *, void *, struct timeval *, size_t *, int *, int *))
RBL_STAT rbl_query_cancel (RBL *rbl, void *qh)
RBL_STAT rbl_query_start (RBL *rbl, u_char *query, void **qh)
RBL_STAT rbl_query_check (RBL *rbl, void *qh, struct timeval *timeout, uint32_t *res)

Variables

static char rbl_c_id [] = "$Id$"

Class Documentation

struct rbl_query

Definition at line 39 of file rbl.c.

Class Members
size_t rq_anslen
u_char rq_buf
void * rq_qh
struct rbl_res_qh

Definition at line 77 of file rbl.c.

Class Members
size_t rq_buflen
int rq_error

Define Documentation

#define MAXPACKET   8192

Definition at line 28 of file rbl.c.

#define RES_UNC_T   unsigned char *

Definition at line 32 of file rbl.c.

#define T_RRSIG   46

Definition at line 35 of file rbl.c.


Function Documentation

void rbl_close ( RBL *  rbl)

Definition at line 289 of file rbl.c.

{
       assert(rbl != NULL);

       if (rbl->rbl_free != NULL)
              rbl->rbl_free(rbl->rbl_closure, rbl);
       else
              free(rbl);
}
void rbl_dns_set_query_cancel ( RBL *  rbl,
int(*)(void *, void *)  func 
)

Definition at line 493 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_dns_cancel = func;
}
void* rbl_dns_set_query_service ( RBL *  rbl,
void *  h 
)

Definition at line 429 of file rbl.c.

{
       void *old;

       assert(rbl != NULL);

       old = rbl->rbl_dns_service;

       rbl->rbl_dns_service = h;

       return old;
}
void rbl_dns_set_query_start ( RBL *  rbl,
int(*)(void *, int, unsigned char *, unsigned char *, size_t, void **)  func 
)

Definition at line 465 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_dns_start = func;
}
void rbl_dns_set_query_waitreply ( RBL *  rbl,
int(*)(void *, void *, struct timeval *, size_t *, int *, int *)  func 
)

Definition at line 522 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_dns_waitreply = func;
}
const u_char* rbl_geterror ( RBL *  rbl)

Definition at line 311 of file rbl.c.

{
       assert(rbl != NULL);

       return rbl->rbl_error;
}
RBL* rbl_init ( void *(*)(void *closure, size_t nbytes)  caller_mallocf,
void(*)(void *closure, void *p)  caller_freef,
void *  closure 
)

Definition at line 251 of file rbl.c.

{
       RBL *new;

       if (caller_mallocf == NULL)
              new = (RBL *) malloc(sizeof(struct rbl_handle));
       else
              new = caller_mallocf(closure, sizeof(struct rbl_handle));

       if (new == NULL)
              return NULL;

       memset(new, '\0', sizeof(struct rbl_handle));

       new->rbl_timeout = RBL_DEFTIMEOUT;
       new->rbl_closure = closure;
       new->rbl_malloc = caller_mallocf;
       new->rbl_free = caller_freef;
       new->rbl_dns_start = rbl_res_query;
       new->rbl_dns_waitreply = rbl_res_waitreply;
       new->rbl_dns_cancel = rbl_res_cancel;

       return new;
}

Here is the call graph for this function:

RBL_STAT rbl_query_cancel ( RBL *  rbl,
void *  qh 
)

Definition at line 544 of file rbl.c.

{
       struct rbl_query *rq;

       assert(rbl != NULL);
       assert(qh != NULL);

       rq = qh;

       rbl->rbl_dns_cancel(rbl->rbl_dns_service, rq->rq_qh);

       if (rbl->rbl_free != NULL)
              rbl->rbl_free(rbl->rbl_closure, rq);
       else
              free(rq);

       return RBL_STAT_OK;
}
RBL_STAT rbl_query_check ( RBL *  rbl,
void *  qh,
struct timeval *  timeout,
uint32_t *  res 
)

Definition at line 635 of file rbl.c.

{
       int dnserr;
       int status;
       int n;
       int type;
       int class;
       int qdcount;
       int ancount;
       struct rbl_query *rq;
       u_char *cp;
       u_char *eom;
       u_char *found = NULL;
       HEADER hdr;
       u_char qname[RBL_MAXHOSTNAMELEN + 1];

       assert(rbl != NULL);
       assert(qh != NULL);

       rq = qh;

       status = rbl->rbl_dns_waitreply(rbl->rbl_dns_service,
                                       rq->rq_qh, timeout, &rq->rq_anslen,
                                       &dnserr, NULL);

       if (status == RBL_DNS_ERROR)
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "error during query");
              return RBL_STAT_ERROR;
       }
       else if (status == RBL_DNS_NOREPLY)
       {
              return RBL_STAT_NOREPLY;
       }
       else if (status == RBL_DNS_EXPIRED)
       {
              return RBL_STAT_EXPIRED;
       }

       /* set up pointers */
       memcpy(&hdr, rq->rq_buf, sizeof hdr);
       cp = (u_char *) rq->rq_buf + HFIXEDSZ;
       eom = (u_char *) rq->rq_buf + rq->rq_anslen;

       /* skip over the name at the front of the answer */
       for (qdcount = ntohs((unsigned short) hdr.qdcount);
            qdcount > 0;
            qdcount--)
       {
              /* copy it first */
              (void) dn_expand((unsigned char *) rq->rq_buf, eom, cp,
                               (char *) qname, sizeof qname);
 
              if ((n = dn_skipname(cp, eom)) < 0)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' reply corrupt", qname);
                     return RBL_STAT_ERROR;
              }
              cp += n;

              /* extract the type and class */
              if (cp + INT16SZ + INT16SZ > eom)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' reply corrupt", qname);
                     return RBL_STAT_ERROR;
              }
              GETSHORT(type, cp);
              GETSHORT(class, cp);
       }

       if (type != T_A || class != C_IN)
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "'%s' unexpected reply type/class", qname);
              return RBL_STAT_ERROR;
       }

       /* if NXDOMAIN, return DKIM_STAT_NOKEY */
       if (hdr.rcode == NXDOMAIN)
              return RBL_STAT_NOTFOUND;

       /* get the answer count */
       ancount = ntohs((unsigned short) hdr.ancount);
       if (ancount == 0)
              return RBL_STAT_NOTFOUND;

       /*
       **  Extract the data from the first TXT answer.
       */

       while (--ancount >= 0 && cp < eom)
       {
              /* grab the label, even though we know what we asked... */
              if ((n = dn_expand((unsigned char *) rq->rq_buf, eom, cp,
                                 (RES_UNC_T) qname, sizeof qname)) < 0)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' reply corrupt", qname);
                     return RBL_STAT_ERROR;
              }
              /* ...and move past it */
              cp += n;

              /* extract the type and class */
              if (cp + INT16SZ + INT16SZ > eom)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' reply corrupt", qname);
                     return RBL_STAT_ERROR;
              }

              GETSHORT(type, cp);
              GETSHORT(class, cp);

              /* skip the TTL */
              cp += INT32SZ;

              /* skip CNAME if found; assume it was resolved */
              if (type == T_CNAME)
              {
                     char chost[RBL_MAXHOSTNAMELEN + 1];

                     n = dn_expand((u_char *) rq->rq_buf, eom, cp,
                                   chost, RBL_MAXHOSTNAMELEN);
                     cp += n;
                     continue;
              }
              else if (type == T_RRSIG)
              {
                     /* get payload length */
                     if (cp + INT16SZ > eom)
                     {
                            snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                                     "'%s' reply corrupt", qname);
                            return RBL_STAT_ERROR;
                     }
                     GETSHORT(n, cp);

                     cp += n;

                     continue;
              }
              else if (type != T_A)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' unexpected reply type/class", qname);
                     return RBL_STAT_ERROR;
              }

              if (found != NULL)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "multiple replies for '%s'", qname);
                     return RBL_STAT_ERROR;
              }

              /* remember where this one started */
              found = cp;

              /* get payload length */
              if (cp + INT16SZ > eom)
              {
                     snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                              "'%s' reply corrupt", qname);
                     return RBL_STAT_ERROR;
              }
              GETSHORT(n, cp);

              /* move forward for now */
              cp += n;
       }

       /* if ancount went below 0, there were no good records */
       if (found == NULL)
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "'%s' reply was unresolved CNAME", qname);
              return RBL_STAT_ERROR;
       }

       /* come back to the one we found */
       cp = found;

       /* get payload length */
       if (cp + INT16SZ > eom)
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "'%s' reply corrupt", qname);
              return RBL_STAT_ERROR;
       }

       GETSHORT(n, cp);
       if (n != sizeof(uint32_t))
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "'%s' reply corrupt", qname);
              return RBL_STAT_ERROR;
       }

       if (cp + n > eom)
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "'%s' reply corrupt", qname);
              return RBL_STAT_ERROR;
       }

       /* extract the payload */
       if (res != NULL)
       {
              uint32_t addr;

              GETLONG(addr, cp);

              *res = addr;
       }

       return RBL_STAT_FOUND;
}
RBL_STAT rbl_query_start ( RBL *  rbl,
u_char *  query,
void **  qh 
)

Definition at line 576 of file rbl.c.

{
       int status;
       struct rbl_query *rq;
       u_char rblquery[RBL_MAXHOSTNAMELEN + 1];

       assert(rbl != NULL);
       assert(query != NULL);
       assert(qh != NULL);

       if (rbl->rbl_qroot[0] == '\0')
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "query root not set");
              return RBL_STAT_INVALID;
       }

       snprintf(rblquery, sizeof rblquery, "%s.%s", query, rbl->rbl_qroot);

       if (rbl->rbl_malloc != NULL)
              rq = rbl->rbl_malloc(rbl->rbl_closure, sizeof(*rq));
       else
              rq = malloc(sizeof(*rq));

       if (rq == NULL)
              return RBL_STAT_NORESOURCE;

       memset(rq, '\0', sizeof *rq);

       status = rbl->rbl_dns_start(rbl->rbl_dns_service, T_A, rblquery,
                                   rq->rq_buf, sizeof rq->rq_buf, &rq->rq_qh);

       if (status == 0)
       {
              *qh = rq;
              return RBL_STAT_OK;
       }
       else
       {
              snprintf(rbl->rbl_error, sizeof rbl->rbl_error,
                       "unable to start query for '%s'", rblquery);
              return RBL_STAT_DNSERROR;
       }
}
static int rbl_res_cancel ( void *  srv,
void *  qh 
) [static]

Definition at line 100 of file rbl.c.

{
       if (qh != NULL)
              free(qh);

       return 0;
}

Here is the caller graph for this function:

static int rbl_res_query ( void *  srv,
int  type,
unsigned char *  query,
unsigned char *  buf,
size_t  buflen,
void **  qh 
) [static]

Definition at line 130 of file rbl.c.

{
       int n;
       int ret;
       struct rbl_res_qh *rq;
       unsigned char qbuf[HFIXEDSZ + MAXPACKET];
#ifdef HAVE_RES_NINIT
       struct __res_state statp;
#endif /* HAVE_RES_NINIT */

#ifdef HAVE_RES_NINIT
       memset(&statp, '\0', sizeof statp);
       res_ninit(&statp);
#endif /* HAVE_RES_NINIT */

#ifdef HAVE_RES_NINIT
       n = res_nmkquery(&statp, QUERY, (char *) query, C_IN, type, NULL, 0,
                        NULL, qbuf, sizeof qbuf);
#else /* HAVE_RES_NINIT */
       n = res_mkquery(QUERY, (char *) query, C_IN, type, NULL, 0, NULL, qbuf,
                       sizeof qbuf);
#endif /* HAVE_RES_NINIT */
       if (n == (size_t) -1)
       {
#ifdef HAVE_RES_NINIT
              res_nclose(&statp);
#endif /* HAVE_RES_NINIT */
              return RBL_DNS_ERROR;
       }

#ifdef HAVE_RES_NINIT
       ret = res_nsend(&statp, qbuf, n, buf, buflen);
#else /* HAVE_RES_NINIT */
       ret = res_send(qbuf, n, buf, buflen);
#endif /* HAVE_RES_NINIT */
       if (ret == -1)
       {
#ifdef HAVE_RES_NINIT
              res_nclose(&statp);
#endif /* HAVE_RES_NINIT */
              return RBL_DNS_ERROR;
       }

#ifdef HAVE_RES_NINIT
       res_nclose(&statp);
#endif /* HAVE_RES_NINIT */

       rq = (struct rbl_res_qh *) malloc(sizeof *rq);
       if (rq == NULL)
              return RBL_DNS_ERROR;

       if (ret == -1)
       {
              rq->rq_error = errno;
              rq->rq_buflen = 0;
       }
       else
       {
              rq->rq_error = 0;
              rq->rq_buflen = (size_t) ret;
       }

       *qh = (void *) rq;

       return RBL_DNS_SUCCESS;
}

Here is the caller graph for this function:

int rbl_res_waitreply ( void *  srv,
void *  qh,
struct timeval *  to,
size_t *  bytes,
int *  error,
int *  dnssec 
)

Definition at line 217 of file rbl.c.

{
       struct rbl_res_qh *rq;

       assert(qh != NULL);

       rq = qh;

       if (bytes != NULL)
              *bytes = rq->rq_buflen;
       if (error != NULL)
              *error = rq->rq_error;

       return RBL_DNS_SUCCESS;
}

Here is the caller graph for this function:

void rbl_setcallbackctx ( RBL *  rbl,
void *  ctx 
)

Definition at line 389 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_cbctx = ctx;
}
void rbl_setcallbackint ( RBL *  rbl,
u_int  cbint 
)

Definition at line 370 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_cbint = cbint;
}
void rbl_setdnscallback ( RBL *  rbl,
void(*)(const void *context)  func 
)

Definition at line 408 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_dns_callback = func;
}
void rbl_setdomain ( RBL *  rbl,
u_char *  qroot 
)

Definition at line 330 of file rbl.c.

{
       assert(rbl != NULL);
       assert(qroot != NULL);

       strncpy(rbl->rbl_qroot, qroot, sizeof rbl->rbl_qroot);
       rbl->rbl_qroot[sizeof rbl->rbl_qroot - 1] = '\0';
}
void rbl_settimeout ( RBL *  rbl,
u_int  timeout 
)

Definition at line 351 of file rbl.c.

{
       assert(rbl != NULL);

       rbl->rbl_timeout = timeout;
}

Variable Documentation

char rbl_c_id[] = "$Id$" [static]

Definition at line 6 of file rbl.c.