Back to index

opendkim  2.6.4
flowrate.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2011, The OpenDKIM Project.  All rights reserved.
00003 */
00004 
00005 #ifndef lint
00006 static char flowrate_c_id[] = "@(#)$Id$";
00007 #endif /* !lint */
00008 
00009 #include "build-config.h"
00010 
00011 #ifdef _FFR_RATE_LIMIT
00012 
00013 /* system includes */
00014 #include <sys/param.h>
00015 #include <sys/types.h>
00016 #include <pthread.h>
00017 #include <time.h>
00018 #include <errno.h>
00019 #include <assert.h>
00020 #include <string.h>
00021 #include <stdlib.h>
00022 
00023 /* libopendkim includes */
00024 #include <dkim-strl.h>
00025 
00026 /* opendkim includes */
00027 #include "flowrate.h"
00028 #include "opendkim.h"
00029 #include "opendkim-db.h"
00030 
00031 /* DATA TYPES */
00032 struct flowdata
00033 {
00034        time_t        fd_since;
00035        unsigned int  fd_limit;
00036        unsigned int  fd_count;
00037 };
00038 
00039 /* GLOBALS */
00040 pthread_mutex_t ratelock;
00041 
00042 /*
00043 **  DKIMF_RATE_CHECK -- conduct a rate limit check, expire data, increment
00044 **
00045 **  Parameters:
00046 **     domain -- domain name being queried (or NULL for unsigned mail)
00047 **     ratedb -- data set containing per-domain rate limits
00048 **     flowdb -- data set containing per-domain flow data (updated)
00049 **     factor -- divisor
00050 **     ttl -- TTL to apply (i.e. data expiration)
00051 **     limit -- limit for this domain (returned)
00052 **
00053 **  Return value:
00054 **     -1 -- error
00055 **     0 -- success
00056 **     1 -- success, and the domain is at or past its limit
00057 */
00058 
00059 int
00060 dkimf_rate_check(const char *domain, DKIMF_DB ratedb, DKIMF_DB flowdb,
00061                  int factor, int ttl, unsigned int *limit)
00062 {
00063        _Bool found = FALSE;
00064        int status;
00065        time_t now;
00066        struct dkimf_db_data dbd;
00067        struct flowdata f;
00068        char limbuf[BUFRSZ];
00069 
00070        assert(ratedb != NULL);
00071        assert(flowdb != NULL);
00072 
00073        if (domain == NULL)
00074               domain = ".";
00075 
00076        memset(&f, '\0', sizeof f);
00077 
00078        pthread_mutex_lock(&ratelock);
00079 
00080        /* get the current flow data, if any */
00081        dbd.dbdata_buffer = (void *) &f;
00082        dbd.dbdata_buflen = sizeof f;
00083        dbd.dbdata_flags = DKIMF_DB_DATA_BINARY;
00084        status = dkimf_db_get(flowdb, (void *) domain, 0, &dbd, 1, &found);
00085        if (status != 0)
00086        {
00087               pthread_mutex_unlock(&ratelock);
00088               return -1;
00089        }
00090 
00091        (void) time(&now);
00092 
00093        /* if none or if it expired, retrieve the limit */
00094        if (!found || f.fd_since + ttl <= now)
00095        {
00096               char *p;
00097 
00098               dbd.dbdata_buffer = limbuf;
00099               dbd.dbdata_buflen = sizeof limbuf;
00100               dbd.dbdata_flags = 0;
00101               status = dkimf_db_get(ratedb, (void *) domain, 0, &dbd, 1,
00102                                     &found);
00103               if (status != 0)
00104               {
00105                      pthread_mutex_unlock(&ratelock);
00106                      return -1;
00107               }
00108               else if (!found)
00109               {
00110                      pthread_mutex_unlock(&ratelock);
00111                      return 0;
00112               }
00113 
00114               f.fd_count = 0;
00115               f.fd_limit = (unsigned int) strtoul(limbuf, &p, 10) / factor;
00116               (void) time(&f.fd_since);
00117               if (*p != '\0')
00118               {
00119                      pthread_mutex_unlock(&ratelock);
00120                      return -1;
00121               }
00122        }
00123 
00124        /* increment the count */
00125        f.fd_count++;
00126 
00127        /* write it back out */
00128        status = dkimf_db_put(flowdb, (void *) domain, strlen(domain),
00129                              &f, sizeof f);
00130        if (status != 0)
00131        {
00132               pthread_mutex_unlock(&ratelock);
00133               return -1;
00134        }
00135 
00136        pthread_mutex_unlock(&ratelock);
00137 
00138        /* copy the limit out */
00139        if (limit != NULL)
00140               *limit = f.fd_limit;
00141 
00142        return (f.fd_count >= f.fd_limit ? 1 : 0);
00143 }
00144 
00145 #endif /* _FFR_RATE_LIMIT */