"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/libspf2/spf_dns_zone.c" (28 Jan 2012, 9815 Bytes) of package /linux/privat/libspf2-1.2.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spf_dns_zone.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * This program is free software; you can redistribute it and/or modify
    3  * it under the terms of either:
    4  *
    5  *   a) The GNU Lesser General Public License as published by the Free
    6  *      Software Foundation; either version 2.1, or (at your option) any
    7  *      later version,
    8  *
    9  *   OR
   10  *
   11  *   b) The two-clause BSD license.
   12  *
   13  * These licenses can be found with the distribution in the file LICENSES
   14  */
   15 
   16 #include "spf_sys_config.h"
   17 
   18 #ifdef STDC_HEADERS
   19 # include <stdio.h>        /* stdin / stdout */
   20 # include <stdlib.h>       /* malloc / free */
   21 #endif
   22 
   23 
   24 #ifdef HAVE_STRING_H
   25 # include <string.h>       /* strstr / strdup */
   26 #else
   27 # ifdef HAVE_STRINGS_H
   28 #  include <strings.h>       /* strstr / strdup */
   29 # endif
   30 #endif
   31 
   32 #ifdef HAVE_MEMORY_H
   33 #include <memory.h>
   34 #endif
   35 #if TIME_WITH_SYS_TIME
   36 # include <sys/time.h>
   37 # include <time.h>
   38 #else
   39 # if HAVE_SYS_TIME_H
   40 #  include <sys/time.h>
   41 # else
   42 #  include <time.h>
   43 # endif
   44 #endif
   45 #ifdef HAVE_NETDB_H
   46 # include <netdb.h>
   47 #endif
   48 #include <ctype.h>
   49 
   50 
   51 #include "spf.h"
   52 #include "spf_dns.h"
   53 #include "spf_internal.h"
   54 #include "spf_dns_internal.h"
   55 #include "spf_dns_zone.h"
   56 
   57 
   58 /**
   59  * @file
   60  *
   61  * This is really little more than a proof-of-concept static zone.
   62  *
   63  * The static zone shouldn't just be an unsorted list that must be
   64  * completely searched each time.  Rather something should be done to
   65  * allow quicker access.  For example, sorting/bsearch, or red-black
   66  * trees, or perfect hashes, or something.
   67  *
   68  * Note that wildcards mean that a domain could match more than one
   69  * record.  The most specific record should match.
   70  */
   71 
   72 
   73 typedef struct
   74 {
   75     SPF_dns_rr_t    **zone;
   76     int               num_zone;     /* This one really is an int. */
   77     int               zone_buf_len; /* This one really is an int. */
   78     SPF_dns_rr_t     *nxdomain;
   79 } SPF_dns_zone_config_t;
   80 
   81 
   82 
   83 static inline SPF_dns_zone_config_t *SPF_voidp2spfhook( void *hook )
   84     { return (SPF_dns_zone_config_t *)hook; }
   85 static inline void *SPF_spfhook2voidp( SPF_dns_zone_config_t *spfhook )
   86     { return (void *)spfhook; }
   87 
   88 
   89 
   90 
   91 /**
   92  * Setting 'exact' to true causes an exact match, including all wildcards,
   93  * and is used for adding records.
   94  */
   95 static SPF_dns_rr_t *
   96 SPF_dns_zone_find(SPF_dns_server_t *spf_dns_server,
   97                 const char *domain, ns_type rr_type,
   98                 int exact)
   99 {
  100     SPF_dns_zone_config_t   *spfhook;
  101     int     i;
  102 
  103     spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
  104 
  105     if (spf_dns_server->debug)
  106         SPF_debugf("zone: Searching for RR %s (%d)", domain, rr_type);
  107 
  108     /* If the record we want or are adding starts with '*.' then it must match
  109      * exactly. */
  110     if (exact || strncmp(domain, "*.", 2) == 0) {
  111         for (i = 0; i < spfhook->num_zone; i++) {
  112             if (spfhook->zone[i]->rr_type == rr_type
  113                     && strcasecmp(spfhook->zone[i]->domain, domain) == 0)
  114                 return spfhook->zone[i];
  115         }
  116         if (spf_dns_server->debug)
  117             SPF_debugf("zone: Exact not found");
  118     }
  119     else {
  120         /* We are looking up a record, so lookup-matching semantics apply. */
  121         size_t  domain_len = strlen(domain);
  122         /* Real resolver would strip trailing '.', so we have to.
  123          * FIXME: doesn't handle wildcard cases - we don't use
  124          * those in test suite. */
  125         if (domain_len && domain[domain_len - 1] == '.')
  126             --domain_len;
  127 
  128         for (i = 0; i < spfhook->num_zone; i++) {
  129             if (spfhook->zone[i]->rr_type != rr_type
  130                     && spfhook->zone[i]->rr_type != ns_t_any) {
  131                 if (spf_dns_server->debug)
  132                     SPF_debugf("zone: Ignoring record rrtype %d",
  133                             spfhook->zone[i]->rr_type);
  134                 continue;
  135             }
  136 
  137             if (strncmp(spfhook->zone[i]->domain, "*.", 2) == 0) {
  138                 size_t  zdomain_len = strlen(spfhook->zone[i]->domain) - 2;
  139                 if ((zdomain_len <= domain_len)
  140                      && strncasecmp(
  141                                 spfhook->zone[i]->domain + 2,
  142                                 domain + (domain_len - zdomain_len),
  143                                 zdomain_len) == 0)
  144                     return spfhook->zone[i];
  145             }
  146             else if (strncasecmp(
  147                         spfhook->zone[i]->domain,
  148                         domain,
  149                         domain_len) == 0 &&
  150                     strlen(spfhook->zone[i]->domain) == domain_len) {
  151                 return spfhook->zone[i];
  152             }
  153         }
  154         if (spf_dns_server->debug)
  155             SPF_debugf("zone: Non-exact not found");
  156     }
  157 
  158     return NULL;
  159 }
  160 
  161 
  162 
  163 static SPF_dns_rr_t *
  164 SPF_dns_zone_lookup(SPF_dns_server_t *spf_dns_server,
  165                 const char *domain, ns_type rr_type, int should_cache)
  166 {
  167     SPF_dns_zone_config_t   *spfhook;
  168     SPF_dns_rr_t            *spfrr;
  169 
  170     spfrr = SPF_dns_zone_find(spf_dns_server, domain, rr_type, FALSE);
  171     if (spfrr) {
  172         SPF_dns_rr_dup(&spfrr, spfrr);
  173         return spfrr;
  174     }
  175 
  176     if (spf_dns_server->layer_below) {
  177         return SPF_dns_lookup(spf_dns_server->layer_below,
  178                         domain, rr_type, should_cache);
  179     }
  180 
  181     spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
  182     SPF_dns_rr_dup(&spfrr, spfhook->nxdomain);
  183 
  184     return spfrr;
  185 }
  186 
  187 
  188 SPF_errcode_t
  189 SPF_dns_zone_add_str(SPF_dns_server_t *spf_dns_server,
  190                 const char *domain, ns_type rr_type,
  191                 SPF_dns_stat_t herrno, const char *data)
  192 {
  193     SPF_dns_zone_config_t   *spfhook;
  194     SPF_dns_rr_t            *spfrr;
  195 
  196     int     err;
  197     int     cnt;
  198 
  199     if (rr_type == ns_t_any) {
  200         if (data)
  201             SPF_error("RR type ANY can not have data.");
  202         if (herrno == NETDB_SUCCESS)
  203             SPF_error("RR type ANY must return a DNS error code.");
  204     }
  205 
  206     spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
  207 
  208     /* try to find an existing record */
  209     spfrr = SPF_dns_zone_find(spf_dns_server, domain, rr_type, TRUE);
  210 
  211     /* create a new record */
  212     if ( spfrr == NULL ) {
  213         /* First make sure we have space for it. */
  214         if ( spfhook->num_zone == spfhook->zone_buf_len ) {
  215             int             new_len;
  216             SPF_dns_rr_t    **new_zone;
  217             int             i;
  218 
  219             new_len = spfhook->zone_buf_len
  220                     + (spfhook->zone_buf_len >> 2) + 4;
  221             new_zone = realloc( spfhook->zone,
  222                     new_len * sizeof( *new_zone ) );
  223             if ( new_zone == NULL )
  224                 return SPF_E_NO_MEMORY;
  225 
  226             for( i = spfhook->zone_buf_len; i < new_len; i++ )
  227                 new_zone[i] = NULL;
  228 
  229             spfhook->zone_buf_len = new_len;
  230             spfhook->zone = new_zone;
  231         }
  232 
  233         /* Now make the new record. */
  234         spfrr = SPF_dns_rr_new_init(spf_dns_server,
  235                         domain, rr_type, 24*60*60, herrno);
  236         if (spfrr == NULL)
  237             return SPF_E_NO_MEMORY;
  238         spfhook->zone[spfhook->num_zone] = spfrr;
  239         spfhook->num_zone++;
  240 
  241         /* We succeeded with the add, but with no data. */
  242         if (herrno != NETDB_SUCCESS)
  243             return SPF_E_SUCCESS;
  244     }
  245 
  246 #define SPF_RR_TRY_REALLOC(rr, i, s) do { \
  247             SPF_errcode_t __err = SPF_dns_rr_buf_realloc(rr, i, s); \
  248             if (__err != SPF_E_SUCCESS) return __err; \
  249         } while(0)
  250 
  251     /*
  252      * initialize stuff
  253      */
  254     cnt = spfrr->num_rr;
  255 
  256     switch (rr_type) {
  257         case ns_t_a:
  258             SPF_RR_TRY_REALLOC(spfrr, cnt, sizeof( spfrr->rr[cnt]->a ));
  259             err = inet_pton( AF_INET, data, &spfrr->rr[cnt]->a );
  260             if ( err <= 0 )
  261                 return SPF_E_INVALID_IP4;
  262             break;
  263 
  264         case ns_t_aaaa:
  265             SPF_RR_TRY_REALLOC(spfrr, cnt, sizeof( spfrr->rr[cnt]->aaaa ));
  266             err = inet_pton( AF_INET6, data, &spfrr->rr[cnt]->aaaa );
  267             if ( err <= 0 )
  268                 return SPF_E_INVALID_IP6;
  269             break;
  270 
  271         case ns_t_mx:
  272             /* Caller passes priority<sp>domain.  We don't use or
  273              * store priority, so discard it. */
  274             while (isdigit(*data)) data++;
  275             while (isspace(*data)) data++;
  276             SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
  277             strcpy( spfrr->rr[cnt]->mx, data );
  278             break;
  279 
  280         case ns_t_txt:
  281         case ns_t_spf:
  282             SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
  283             strcpy( spfrr->rr[cnt]->txt, data );
  284             break;
  285 
  286         case ns_t_ptr:
  287             SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
  288             strcpy( spfrr->rr[cnt]->ptr, data );
  289             break;
  290 
  291         case ns_t_any:
  292             if ( data )
  293                 SPF_error( "RR type ANY can not have data.");
  294             if ( herrno == NETDB_SUCCESS )
  295                 SPF_error( "RR type ANY must return a DNS error code.");
  296             SPF_error( "RR type ANY can not have multiple RR.");
  297             break;
  298 
  299         default:
  300             SPF_error( "Invalid RR type" );
  301             break;
  302     }
  303 
  304     spfrr->num_rr = cnt + 1;
  305 
  306     return SPF_E_SUCCESS;
  307 }
  308 
  309 
  310 
  311 static void
  312 SPF_dns_zone_free(SPF_dns_server_t *spf_dns_server)
  313 {
  314     SPF_dns_zone_config_t   *spfhook;
  315     int             i;
  316 
  317     SPF_ASSERT_NOTNULL(spf_dns_server);
  318     spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
  319 
  320     if (spfhook) {
  321         if (spfhook->zone) {
  322             for (i = 0; i < spfhook->zone_buf_len; i++) {
  323                 if (spfhook->zone[i])
  324                     SPF_dns_rr_free(spfhook->zone[i]);
  325             }
  326             free(spfhook->zone);
  327         }
  328         if (spfhook->nxdomain)
  329             SPF_dns_rr_free(spfhook->nxdomain);
  330         free(spfhook);
  331     }
  332 
  333     free(spf_dns_server);
  334 }
  335 
  336 SPF_dns_server_t *
  337 SPF_dns_zone_new(SPF_dns_server_t *layer_below,
  338                 const char *name, int debug)
  339 {
  340     SPF_dns_server_t        *spf_dns_server;
  341     SPF_dns_zone_config_t   *spfhook;
  342 
  343     spf_dns_server = malloc(sizeof(SPF_dns_server_t));
  344     if (spf_dns_server == NULL)
  345         return NULL;
  346     memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
  347 
  348     spf_dns_server->hook = malloc(sizeof(SPF_dns_zone_config_t));
  349     if (spf_dns_server->hook == NULL) {
  350         free(spf_dns_server);
  351         return NULL;
  352     }
  353     memset(spf_dns_server->hook, 0, sizeof(SPF_dns_zone_config_t));
  354 
  355     if (name ==  NULL)
  356         name = "zone";
  357 
  358     spf_dns_server->destroy      = SPF_dns_zone_free;
  359     spf_dns_server->lookup       = SPF_dns_zone_lookup;
  360     spf_dns_server->get_spf      = NULL;
  361     spf_dns_server->get_exp      = NULL;
  362     spf_dns_server->add_cache    = NULL;
  363     spf_dns_server->layer_below  = layer_below;
  364     spf_dns_server->name         = name;
  365     spf_dns_server->debug        = debug;
  366 
  367     spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
  368 
  369     spfhook->zone_buf_len = 32;
  370     spfhook->num_zone = 0;
  371     spfhook->zone = calloc(spfhook->zone_buf_len, sizeof(*spfhook->zone));
  372 
  373     if (spfhook->zone == NULL) {
  374         free(spfhook);
  375         free(spf_dns_server);
  376         return NULL;
  377     }
  378 
  379     /* XXX This might have to return NO_DATA sometimes. */
  380     spfhook->nxdomain = SPF_dns_rr_new_init(spf_dns_server,
  381                     "", ns_t_any, 24 * 60 * 60, HOST_NOT_FOUND);
  382     if (spfhook->nxdomain == NULL) {
  383         free(spfhook->zone);
  384         free(spfhook);
  385         free(spf_dns_server);
  386         return NULL;
  387     }
  388 
  389     return spf_dns_server;
  390 }