"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 }