00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "spf_sys_config.h"
00017
00018 #ifdef STDC_HEADERS
00019 # include <stdio.h>
00020 # include <stdlib.h>
00021 #endif
00022
00023
00024 #ifdef HAVE_STRING_H
00025 # include <string.h>
00026 #else
00027 # ifdef HAVE_STRINGS_H
00028 # include <strings.h>
00029 # endif
00030 #endif
00031
00032 #ifdef HAVE_MEMORY_H
00033 #include <memory.h>
00034 #endif
00035 #if TIME_WITH_SYS_TIME
00036 # include <sys/time.h>
00037 # include <time.h>
00038 #else
00039 # if HAVE_SYS_TIME_H
00040 # include <sys/time.h>
00041 # else
00042 # include <time.h>
00043 # endif
00044 #endif
00045 #ifdef HAVE_NETDB_H
00046 # include <netdb.h>
00047 #endif
00048 #include <ctype.h>
00049
00050
00051 #include "spf.h"
00052 #include "spf_dns.h"
00053 #include "spf_internal.h"
00054 #include "spf_dns_internal.h"
00055 #include "spf_dns_zone.h"
00056
00057
00073 typedef struct
00074 {
00075 SPF_dns_rr_t **zone;
00076 int num_zone;
00077 int zone_buf_len;
00078 SPF_dns_rr_t *nxdomain;
00079 } SPF_dns_zone_config_t;
00080
00081
00082
00083 static inline SPF_dns_zone_config_t *SPF_voidp2spfhook( void *hook )
00084 { return (SPF_dns_zone_config_t *)hook; }
00085 static inline void *SPF_spfhook2voidp( SPF_dns_zone_config_t *spfhook )
00086 { return (void *)spfhook; }
00087
00088
00089
00090
00095 static SPF_dns_rr_t *
00096 SPF_dns_zone_find(SPF_dns_server_t *spf_dns_server,
00097 const char *domain, ns_type rr_type,
00098 int exact)
00099 {
00100 SPF_dns_zone_config_t *spfhook;
00101 int i;
00102
00103 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
00104
00105 if (spf_dns_server->debug)
00106 SPF_debugf("zone: Searching for RR %s (%d)", domain, rr_type);
00107
00108
00109
00110 if (exact || strncmp(domain, "*.", 2) == 0) {
00111 for (i = 0; i < spfhook->num_zone; i++) {
00112 if (spfhook->zone[i]->rr_type == rr_type
00113 && strcasecmp(spfhook->zone[i]->domain, domain) == 0)
00114 return spfhook->zone[i];
00115 }
00116 if (spf_dns_server->debug)
00117 SPF_debugf("zone: Exact not found");
00118 }
00119 else {
00120
00121 size_t domain_len = strlen(domain);
00122
00123
00124
00125 if (domain_len && domain[domain_len - 1] == '.')
00126 --domain_len;
00127
00128 for (i = 0; i < spfhook->num_zone; i++) {
00129 if (spfhook->zone[i]->rr_type != rr_type
00130 && spfhook->zone[i]->rr_type != ns_t_any) {
00131 if (spf_dns_server->debug)
00132 SPF_debugf("zone: Ignoring record rrtype %d",
00133 spfhook->zone[i]->rr_type);
00134 continue;
00135 }
00136
00137 if (strncmp(spfhook->zone[i]->domain, "*.", 2) == 0) {
00138 size_t zdomain_len = strlen(spfhook->zone[i]->domain) - 2;
00139 if ((zdomain_len <= domain_len)
00140 && strncasecmp(
00141 spfhook->zone[i]->domain + 2,
00142 domain + (domain_len - zdomain_len),
00143 zdomain_len) == 0)
00144 return spfhook->zone[i];
00145 }
00146 else if (strncasecmp(
00147 spfhook->zone[i]->domain,
00148 domain,
00149 domain_len) == 0 &&
00150 strlen(spfhook->zone[i]->domain) == domain_len) {
00151 return spfhook->zone[i];
00152 }
00153 }
00154 if (spf_dns_server->debug)
00155 SPF_debugf("zone: Non-exact not found");
00156 }
00157
00158 return NULL;
00159 }
00160
00161
00162
00163 static SPF_dns_rr_t *
00164 SPF_dns_zone_lookup(SPF_dns_server_t *spf_dns_server,
00165 const char *domain, ns_type rr_type, int should_cache)
00166 {
00167 SPF_dns_zone_config_t *spfhook;
00168 SPF_dns_rr_t *spfrr;
00169
00170 spfrr = SPF_dns_zone_find(spf_dns_server, domain, rr_type, FALSE);
00171 if (spfrr) {
00172 SPF_dns_rr_dup(&spfrr, spfrr);
00173 return spfrr;
00174 }
00175
00176 if (spf_dns_server->layer_below) {
00177 return SPF_dns_lookup(spf_dns_server->layer_below,
00178 domain, rr_type, should_cache);
00179 }
00180
00181 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
00182 SPF_dns_rr_dup(&spfrr, spfhook->nxdomain);
00183
00184 return spfrr;
00185 }
00186
00187
00188 SPF_errcode_t
00189 SPF_dns_zone_add_str(SPF_dns_server_t *spf_dns_server,
00190 const char *domain, ns_type rr_type,
00191 SPF_dns_stat_t herrno, const char *data)
00192 {
00193 SPF_dns_zone_config_t *spfhook;
00194 SPF_dns_rr_t *spfrr;
00195
00196 int err;
00197 int cnt;
00198
00199 if (rr_type == ns_t_any) {
00200 if (data)
00201 SPF_error("RR type ANY can not have data.");
00202 if (herrno == NETDB_SUCCESS)
00203 SPF_error("RR type ANY must return a DNS error code.");
00204 }
00205
00206 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
00207
00208
00209 spfrr = SPF_dns_zone_find(spf_dns_server, domain, rr_type, TRUE);
00210
00211
00212 if ( spfrr == NULL ) {
00213
00214 if ( spfhook->num_zone == spfhook->zone_buf_len ) {
00215 int new_len;
00216 SPF_dns_rr_t **new_zone;
00217 int i;
00218
00219 new_len = spfhook->zone_buf_len
00220 + (spfhook->zone_buf_len >> 2) + 4;
00221 new_zone = realloc( spfhook->zone,
00222 new_len * sizeof( *new_zone ) );
00223 if ( new_zone == NULL )
00224 return SPF_E_NO_MEMORY;
00225
00226 for( i = spfhook->zone_buf_len; i < new_len; i++ )
00227 new_zone[i] = NULL;
00228
00229 spfhook->zone_buf_len = new_len;
00230 spfhook->zone = new_zone;
00231 }
00232
00233
00234 spfrr = SPF_dns_rr_new_init(spf_dns_server,
00235 domain, rr_type, 24*60*60, herrno);
00236 if (spfrr == NULL)
00237 return SPF_E_NO_MEMORY;
00238 spfhook->zone[spfhook->num_zone] = spfrr;
00239 spfhook->num_zone++;
00240
00241
00242 if (herrno != NETDB_SUCCESS)
00243 return SPF_E_SUCCESS;
00244 }
00245
00246 #define SPF_RR_TRY_REALLOC(rr, i, s) do { \
00247 SPF_errcode_t __err = SPF_dns_rr_buf_realloc(rr, i, s); \
00248 if (__err != SPF_E_SUCCESS) return __err; \
00249 } while(0)
00250
00251
00252
00253
00254 cnt = spfrr->num_rr;
00255
00256 switch (rr_type) {
00257 case ns_t_a:
00258 SPF_RR_TRY_REALLOC(spfrr, cnt, sizeof( spfrr->rr[cnt]->a ));
00259 err = inet_pton( AF_INET, data, &spfrr->rr[cnt]->a );
00260 if ( err <= 0 )
00261 return SPF_E_INVALID_IP4;
00262 break;
00263
00264 case ns_t_aaaa:
00265 SPF_RR_TRY_REALLOC(spfrr, cnt, sizeof( spfrr->rr[cnt]->aaaa ));
00266 err = inet_pton( AF_INET6, data, &spfrr->rr[cnt]->aaaa );
00267 if ( err <= 0 )
00268 return SPF_E_INVALID_IP6;
00269 break;
00270
00271 case ns_t_mx:
00272
00273
00274 while (isdigit(*data)) data++;
00275 while (isspace(*data)) data++;
00276 SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
00277 strcpy( spfrr->rr[cnt]->mx, data );
00278 break;
00279
00280 case ns_t_txt:
00281 case ns_t_spf:
00282 SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
00283 strcpy( spfrr->rr[cnt]->txt, data );
00284 break;
00285
00286 case ns_t_ptr:
00287 SPF_RR_TRY_REALLOC(spfrr, cnt, strlen( data ) + 1);
00288 strcpy( spfrr->rr[cnt]->ptr, data );
00289 break;
00290
00291 case ns_t_any:
00292 if ( data )
00293 SPF_error( "RR type ANY can not have data.");
00294 if ( herrno == NETDB_SUCCESS )
00295 SPF_error( "RR type ANY must return a DNS error code.");
00296 SPF_error( "RR type ANY can not have multiple RR.");
00297 break;
00298
00299 default:
00300 SPF_error( "Invalid RR type" );
00301 break;
00302 }
00303
00304 spfrr->num_rr = cnt + 1;
00305
00306 return SPF_E_SUCCESS;
00307 }
00308
00309
00310
00311 static void
00312 SPF_dns_zone_free(SPF_dns_server_t *spf_dns_server)
00313 {
00314 SPF_dns_zone_config_t *spfhook;
00315 int i;
00316
00317 SPF_ASSERT_NOTNULL(spf_dns_server);
00318 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
00319
00320 if (spfhook) {
00321 if (spfhook->zone) {
00322 for (i = 0; i < spfhook->zone_buf_len; i++) {
00323 if (spfhook->zone[i])
00324 SPF_dns_rr_free(spfhook->zone[i]);
00325 }
00326 free(spfhook->zone);
00327 }
00328 if (spfhook->nxdomain)
00329 SPF_dns_rr_free(spfhook->nxdomain);
00330 free(spfhook);
00331 }
00332
00333 free(spf_dns_server);
00334 }
00335
00336 SPF_dns_server_t *
00337 SPF_dns_zone_new(SPF_dns_server_t *layer_below,
00338 const char *name, int debug)
00339 {
00340 SPF_dns_server_t *spf_dns_server;
00341 SPF_dns_zone_config_t *spfhook;
00342
00343 spf_dns_server = malloc(sizeof(SPF_dns_server_t));
00344 if (spf_dns_server == NULL)
00345 return NULL;
00346 memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
00347
00348 spf_dns_server->hook = malloc(sizeof(SPF_dns_zone_config_t));
00349 if (spf_dns_server->hook == NULL) {
00350 free(spf_dns_server);
00351 return NULL;
00352 }
00353 memset(spf_dns_server->hook, 0, sizeof(SPF_dns_zone_config_t));
00354
00355 if (name == NULL)
00356 name = "zone";
00357
00358 spf_dns_server->destroy = SPF_dns_zone_free;
00359 spf_dns_server->lookup = SPF_dns_zone_lookup;
00360 spf_dns_server->get_spf = NULL;
00361 spf_dns_server->get_exp = NULL;
00362 spf_dns_server->add_cache = NULL;
00363 spf_dns_server->layer_below = layer_below;
00364 spf_dns_server->name = name;
00365 spf_dns_server->debug = debug;
00366
00367 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
00368
00369 spfhook->zone_buf_len = 32;
00370 spfhook->num_zone = 0;
00371 spfhook->zone = calloc(spfhook->zone_buf_len, sizeof(*spfhook->zone));
00372
00373 if (spfhook->zone == NULL) {
00374 free(spfhook);
00375 free(spf_dns_server);
00376 return NULL;
00377 }
00378
00379
00380 spfhook->nxdomain = SPF_dns_rr_new_init(spf_dns_server,
00381 "", ns_t_any, 24 * 60 * 60, HOST_NOT_FOUND);
00382 if (spfhook->nxdomain == NULL) {
00383 free(spfhook->zone);
00384 free(spfhook);
00385 free(spf_dns_server);
00386 return NULL;
00387 }
00388
00389 return spf_dns_server;
00390 }