libspf2 1.2.11
spf_compile.c
Go to the documentation of this file.
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#include "spf_internal.h"
18
19
20#ifdef STDC_HEADERS
21# include <stdio.h> /* stdin / stdout */
22# include <stdlib.h> /* malloc / free */
23# include <ctype.h> /* isupper / tolower */
24#endif
25
26#ifdef HAVE_INTTYPES_H
27#include <inttypes.h>
28#endif
29
30#ifdef HAVE_STRING_H
31# include <string.h> /* strstr / strdup */
32#else
33# ifdef HAVE_STRINGS_H
34# include <strings.h> /* strstr / strdup */
35# endif
36#endif
37
38
39
40#undef SPF_ALLOW_DEPRECATED_DEFAULT
41
42#include "spf.h"
43#include "spf_internal.h"
44#include "spf_response.h"
45#include "spf_record.h"
46
47typedef
48enum SPF_cidr_enum {
51
52typedef
53enum SPF_domspec_enum {
56
62#define SPF_RECORD_BUFSIZ 4096
63
64#define ALIGN_DECL(decl) union { double d; long l; decl } __attribute__((aligned(_ALIGN_SZ))) u
65#define ALIGNED_DECL(var) u.var
66
67
68
69typedef
70struct SPF_mechtype_struct
71{
72 unsigned char mech_type;
73 unsigned char is_dns_mech;
77
78static const SPF_mechtype_t spf_mechtypes[] = {
89};
90
91#define spf_num_mechanisms \
92 sizeof(spf_mechtypes) / sizeof(spf_mechtypes[0])
93
94static const SPF_mechtype_t *
95SPF_mechtype_find(int mech_type)
96{
97 size_t i;
98 for (i = 0; i < spf_num_mechanisms; i++) {
99 if (spf_mechtypes[i].mech_type == mech_type)
100 return &spf_mechtypes[i];
101 }
102 return NULL;
103}
104
105__attribute__((warn_unused_result))
106static int
107SPF_c_ensure_capacity(void **datap, size_t *sizep, size_t length)
108{
109 size_t size = *sizep;
110 if (length > size)
111 size = length + (length / 4);
112 if (size > *sizep) {
113 void *tmp = realloc(*datap, size);
114 if (!tmp)
115 return -1;
116 // memset(tmp + *sizep, 'C', (size - *sizep));
117 *datap = tmp;
118 *sizep = size;
119 }
120 return 0;
121}
122
132static SPF_errcode_t
133SPF_c_parse_cidr_ip6(SPF_response_t *spf_response,
134 unsigned char *maskp,
135 const char *src)
136{
137 int mask;
138
139 /*
140 if (spf_server->debug > 2)
141 SPF_debugf("Parsing ip6 CIDR starting at %s", src);
142 */
143
144 mask = strtoul(src + 1, NULL, 10);
145
146 if (mask > 128) {
148 NULL, src,
149 "Invalid IPv6 CIDR netmask (>128)");
150 }
151 else if (mask == 0) {
153 NULL, src,
154 "Invalid IPv6 CIDR netmask (=0)");
155 }
156 else if (mask == 128) {
157 mask = 0;
158 }
159
160 *maskp = mask;
161
162 return SPF_E_SUCCESS;
163}
164
174static SPF_errcode_t
175SPF_c_parse_cidr_ip4(SPF_response_t *spf_response,
176 unsigned char *maskp,
177 const char *src)
178{
179 int mask;
180
181 /*
182 if (spf_server->debug > 2)
183 SPF_debugf("Parsing ip4 CIDR starting at %s", src);
184 */
185
186 mask = strtoul(src + 1, NULL, 10);
187
188 if ( mask > 32 ) {
190 NULL, src,
191 "Invalid IPv4 CIDR netmask (>32)");
192 }
193 else if ( mask == 0 ) {
195 NULL, src,
196 "Invalid IPv4 CIDR netmask (=0)");
197 }
198 else if ( mask == 32 ) {
199 mask = 0;
200 }
201
202 *maskp = mask;
203
204 return SPF_E_SUCCESS;
205}
206
212static SPF_errcode_t
213SPF_c_parse_cidr(SPF_response_t *spf_response,
214 SPF_data_cidr_t *data,
215 const char *src, size_t *src_len)
216{
217 SPF_errcode_t err;
218 size_t idx;
219
220 memset(data, 0, sizeof(SPF_data_cidr_t));
221 data->parm_type = PARM_CIDR;
222
223 /* Find the beginning of the CIDR length notation.
224 * XXX This assumes that there is a non-digit in the string.
225 * This is always true for SPF records with domainspecs, since
226 * there has to be an = or a : before it. */
227 idx = *src_len - 1;
228 while (idx > 0 && isdigit( (unsigned char)(src[idx]) ))
229 idx--;
230
231 /* Something is frying my brain and I can't pull an invariant
232 * out of this suitable for resetting *endp. So I nested the
233 * 'if's instead. Perhaps I'll manage to refactor later. */
234
235 /* If we have a slash which isn't the last character. */
236 if (idx < (*src_len - 1) && src[idx] == '/') {
237 if (idx > 0 && src[idx - 1] == '/') {
238 /* get IPv6 CIDR length */
239 err = SPF_c_parse_cidr_ip6(spf_response, &data->ipv6, &src[idx]);
240 if (err)
241 return err;
242 /* now back up and see if there is a ipv4 cidr length */
243 *src_len = idx - 1; /* The index of the first '/' */
244 idx = *src_len - 1; /* Last character of what is before. */
245 while (idx > 0 && isdigit( (unsigned char)(src[idx]) ))
246 idx--;
247
248 /* get IPv4 CIDR length */
249 if (idx < (*src_len - 1) && src[idx] == '/') {
250 /* - we know that strtoul terminates on the
251 * '/' so we don't need to null-terminate the
252 * input string. */
253 err = SPF_c_parse_cidr_ip4(spf_response, &data->ipv4, &src[idx]);
254 if (err)
255 return err;
256 *src_len = idx;
257 }
258 }
259 else {
260 /* get IPv4 CIDR length */
261 err = SPF_c_parse_cidr_ip4(spf_response, &data->ipv4, &src[idx]);
262 if (err)
263 return err;
264 *src_len = idx;
265 }
266 }
267
268 return SPF_E_SUCCESS;
269}
270
271static SPF_errcode_t
272SPF_c_parse_var(SPF_response_t *spf_response, SPF_data_var_t *data,
273 const char *src, int is_mod)
274{
275 const char *token;
276 const char *p;
277 char c;
278 int val;
279
280 memset(data, 0, sizeof(SPF_data_var_t));
281
282 p = src;
283
284 /* URL encoding */
285 c = *p;
286 if ( isupper( (unsigned char)( c ) ) )
287 {
288 data->url_encode = TRUE;
289 c = tolower(c);
290 }
291 else
292 data->url_encode = FALSE;
293
294#define SPF_CHECK_IN_MODIFIER() \
295 if ( !is_mod ) \
296 return SPF_response_add_error_ptr(spf_response, \
297 SPF_E_INVALID_VAR, NULL, p, \
298 "'%c' macro is only valid in modifiers", c);
299
300 switch ( c )
301 {
302 case 'l': /* local-part of envelope-sender */
303 data->parm_type = PARM_LP_FROM;
304 break;
305
306 case 's': /* envelope-sender */
307 data->parm_type = PARM_ENV_FROM;
308 break;
309
310 case 'o': /* envelope-domain */
311 data->parm_type = PARM_DP_FROM;
312 break;
313
314 case 'd': /* current-domain */
315 data->parm_type = PARM_CUR_DOM;
316 break;
317
318 case 'i': /* SMTP client IP */
320 break;
321
322 case 'c': /* SMTP client IP (pretty) */
325 break;
326
327 case 't': /* time in UTC epoch secs */
329 data->parm_type = PARM_TIME;
330 break;
331
332 case 'p': /* SMTP client domain name */
334 break;
335
336 case 'v': /* IP ver str - in-addr/ip6 */
338 break;
339
340 case 'h': /* HELO/EHLO domain */
341 data->parm_type = PARM_HELO_DOM;
342 break;
343
344 case 'r': /* receiving domain */
346 data->parm_type = PARM_REC_DOM;
347 break;
348
349 default:
351 NULL, p,
352 "Unknown variable '%c'", c);
353 }
354 p++;
355 token = p;
356
357 /* get the number of subdomains to truncate to */
358 val = 0;
359 while ( isdigit( (unsigned char)( *p ) ) )
360 {
361 val *= 10;
362 val += *p - '0';
363 p++;
364 }
365 if ( val > 128 || (val <= 0 && p != token) )
366 return SPF_response_add_error_ptr(spf_response, SPF_E_BIG_SUBDOM,
367 NULL, token,
368 "Subdomain truncation depth too large");
369 data->num_rhs = val;
370 token = p;
371
372 /* should the string be reversed? */
373 if ( *p == 'r' )
374 {
375 data->rev = 1;
376 p++;
377 }
378 else
379 data->rev = FALSE;
380 token = p;
381
382
383 /* check for delimiters */
384 data->delim_dot = FALSE;
385 data->delim_dash = FALSE;
386 data->delim_plus = FALSE;
387 data->delim_equal = FALSE;
388 data->delim_bar = FALSE;
389 data->delim_under = FALSE;
390
391 /*vi:{*/
392 if ( *p == '}' )
393 data->delim_dot = TRUE;
394
395 /*vi:{*/
396 while( *p != '}' )
397 {
398 token = p;
399 switch( *p )
400 {
401 case '.':
402 data->delim_dot = TRUE;
403 break;
404
405 case '-':
406 data->delim_dash = TRUE;
407 break;
408
409 case '+':
410 data->delim_plus = TRUE;
411 break;
412
413 case '=':
414 data->delim_equal = TRUE;
415 break;
416
417 case '|':
418 data->delim_bar = TRUE;
419 break;
420
421 case '_':
422 data->delim_under = TRUE;
423 break;
424
425 default:
426 return SPF_response_add_error_ptr(spf_response,
428 "Invalid delimiter '%c'", *p);
429 }
430 p++;
431 }
432 p++;
433 token = p;
434
435
436 return SPF_E_SUCCESS;
437}
438
439
440 /* Sorry, Wayne. */
441#define SPF_ADD_LEN_TO(_val, _len, _max) do { \
442 if ( (_val) + _align_sz(_len) > (_max) ) { \
443 return SPF_response_add_error_ptr(spf_response, \
444 big_err, NULL, src, \
445 "SPF domainspec too long " \
446 "(%d chars, %d max)", \
447 (_val) + (_len), _max); \
448 } \
449 (_val) += _align_sz(_len); \
450 } while(0)
451
452#define SPF_INIT_STRING_LITERAL(_avail) do { \
453 data->ds.parm_type = PARM_STRING; \
454 data->ds.len = 0; \
455 /* Magic numbers for x/Nc in gdb. */ \
456 data->ds.__unused0 = 0xba; data->ds.__unused1 = 0xbe; \
457 dst = SPF_data_str( data ); \
458 ds_avail = _avail - sizeof(SPF_data_t); \
459 ds_len = 0; \
460 } while(0)
461
462#define SPF_ENSURE_STRING_AVAIL(_len) do { \
463 if (ds_len + _len > ds_avail) \
464 return SPF_response_add_error_ptr(spf_response, \
465 SPF_E_BIG_STRING, NULL, src, \
466 "String literal fragment too long " \
467 "(%d chars, %d max)", \
468 ds_len, ds_avail); \
469 } while(0)
470
471#define SPF_FINI_STRING_LITERAL() do { \
472 if ( ds_len > 0 ) { \
473 if ( ds_len > SPF_MAX_STR_LEN ) { \
474 return SPF_response_add_error_ptr(spf_response, \
475 SPF_E_BIG_STRING, NULL, src, \
476 "String literal too long " \
477 "(%d chars, %d max)", \
478 ds_len, SPF_MAX_STR_LEN); \
479 } \
480 data->ds.len = ds_len; \
481 len = sizeof( *data ) + ds_len; \
482 SPF_ADD_LEN_TO(*data_used, len, data_avail); \
483 data = SPF_data_next( data ); \
484 ds_len = 0; \
485 } \
486 } while(0)
487
505static SPF_errcode_t
506SPF_c_parse_macro(SPF_server_t *spf_server,
507 SPF_response_t *spf_response,
508 SPF_data_t *data, size_t *data_used, size_t data_avail,
509 const char *src, size_t src_len,
510 SPF_errcode_t big_err,
511 int is_mod)
512{
513 SPF_errcode_t err;
514 /* Generic parsing iterators and boundaries */
515 size_t idx;
516 size_t len;
517 /* For parsing strings. */
518 char *dst;
519 size_t ds_avail;
520 size_t ds_len;
521
522 if (spf_server->debug)
523 SPF_debugf("Parsing macro starting at %s", src);
524
525#if 0
526 if ((void *)data != _align_ptr((void *)data))
527 SPF_errorf("Data pointer %p is not aligned: Cannot compile.",
528 data);
529#endif
530
531 /*
532 * Create the data blocks
533 */
534 idx = 0;
535
536 /* Initialise the block as a string. If ds_len == 0 later, we
537 * will just clobber it. */
538 SPF_INIT_STRING_LITERAL(data_avail - *data_used);
539
540 // while ( p != end ) {
541 while (idx < src_len) {
542 if (spf_server->debug > 3)
543 SPF_debugf("Current data is at %p", data);
544 /* Either the unit is terminated by a space, or we hit a %.
545 * We should only hit a space if we run past src_len. */
546 len = strcspn(&src[idx], " %"); // XXX Also tab?
547 if (len > 0) { /* An optimisation */
548 /* Don't over-run into the CIDR. */
549 if (idx + len > src_len)
550 len = src_len - idx;
551 if (spf_server->debug > 3)
552 SPF_debugf("Adding string literal (%lu): '%*.*s'",
553 (unsigned long)len,
554 (int)len, (int)len, &src[idx]);
555 /* XXX Bounds-check here. */
557 memcpy(dst, &src[idx], len);
558 ds_len += len;
559 dst += len;
560 idx += len;
561
562 /* If len == 0 then we never entered the while(). Thus
563 * if idx == src_len, then len != 0 and we reach this test.
564 */
565 }
566 /* However, this logic is overcomplex and I am a simpleton,
567 * so I have moved it out of the condition above. */
568 if (idx == src_len)
569 break;
570
571 /* Now, we must have a %-escape code, since if we hit a
572 * space, then we are at the end.
573 * Incrementing idx consumes the % we hit first, and then
574 * we switch on the following character, which also
575 * increments idx. */
576 idx++;
577 switch (src[idx]) {
578 case '%':
579 if (spf_server->debug > 3)
580 SPF_debugf("Adding literal %%");
582 *dst++ = '%';
583 ds_len++;
584 idx++;
585 break;
586
587 case '_':
588 if (spf_server->debug > 3)
589 SPF_debugf("Adding literal space");
591 *dst++ = ' ';
592 ds_len++;
593 idx++;
594 break;
595
596 case '-':
597 if (spf_server->debug > 3)
598 SPF_debugf("Adding escaped space");
600 *dst++ = '%'; *dst++ = '2'; *dst++ = '0';
601 ds_len += 3;
602 idx++;
603 break;
604
605 default:
606 if (spf_server->debug > 3)
607 SPF_debugf("Adding illegal %%-follower '%c' at %d",
608 src[idx], idx);
609 /* SPF spec says to treat it as a literal, not
610 * SPF_E_INVALID_ESC */
611 /* FIXME issue a warning? */
613 *dst++ = '%';
614 ds_len++;
615 break;
616
617 case '{': /*vi:}*/
619 if (spf_server->debug > 3)
620 SPF_debugf("Adding macro, data is at %p", data);
621
622 /* this must be a variable */
623 idx++;
624 err = SPF_c_parse_var(spf_response, &data->dv, &src[idx], is_mod);
625 if (err != SPF_E_SUCCESS)
626 return err;
627 idx += strcspn(&src[idx], "} ");
628 if (src[idx] == '}')
629 idx++;
630 else if (src[idx] == ' ')
631 return SPF_response_add_error_ptr(spf_response,
633 src, &src[idx],
634 "Unterminated variable?");
635
636
637 len = SPF_data_len(data);
638 SPF_ADD_LEN_TO(*data_used, len, data_avail);
639 data = SPF_data_next( data );
640 if (spf_server->debug > 3)
641 SPF_debugf("Next data is at %p", data);
642
643 SPF_INIT_STRING_LITERAL(data_avail - *data_used);
644
645 break;
646 }
647 }
648
650
651 return SPF_E_SUCCESS;
652
653}
654
655/* What a fuck-ugly prototype. */
670static SPF_errcode_t
671SPF_c_parse_domainspec(SPF_server_t *spf_server,
672 SPF_response_t *spf_response,
673 SPF_data_t *data, size_t *data_used, size_t data_avail,
674 const char *src, size_t src_len,
675 SPF_errcode_t big_err,
676 SPF_cidr_t cidr_ok, int is_mod)
677{
678 SPF_errcode_t err;
679 /* Generic parsing iterators and boundaries */
680 size_t len;
681
682 if (spf_server->debug)
683 SPF_debugf("Parsing domainspec starting at %s, cidr is %s",
684 src,
685 cidr_ok == CIDR_OPTIONAL ? "optional" :
686 cidr_ok == CIDR_ONLY ? "only" :
687 cidr_ok == CIDR_NONE ? "forbidden" :
688 "ERROR!"
689 );
690
691 /*
692 * create the CIDR length info
693 */
694 if (cidr_ok == CIDR_OPTIONAL || cidr_ok == CIDR_ONLY) {
695 err = SPF_c_parse_cidr(spf_response, &data->dc, src, &src_len);
696 if (err != SPF_E_SUCCESS)
697 return err;
698 if (data->dc.ipv4 != 0 || data->dc.ipv6 != 0) {
699 len = SPF_data_len(data);
700 SPF_ADD_LEN_TO(*data_used, len, data_avail);
701 data = SPF_data_next(data);
702 }
703
704 if (cidr_ok == CIDR_ONLY && src_len > 0) {
705 /* We had a mechanism followed by a '/', thus it HAS to be
706 * a CIDR, and the peculiar-looking error message is
707 * justified. However, we don't know _which_ CIDR. */
708 return SPF_response_add_error_ptr(spf_response,
710 NULL, src,
711 "Invalid CIDR after mechanism");
712 }
713 }
714
715 return SPF_c_parse_macro(spf_server, spf_response,
716 data, data_used, data_avail,
717 src, src_len, big_err, is_mod);
718}
719
720
726static SPF_errcode_t
727SPF_c_parse_ip4(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
728{
729 const char *end;
730 const char *p;
731
732 char buf[ INET6_ADDRSTRLEN ];
733 size_t len;
734 SPF_errcode_t err;
735
736 unsigned char mask;
737 struct in_addr *addr;
738
739 start++;
740 len = strcspn(start, " ");
741 end = start + len;
742 p = end - 1;
743
744 mask = 0;
745 while (isdigit( (unsigned char)(*p) ))
746 p--;
747 if (p != (end - 1) && *p == '/') {
748 err = SPF_c_parse_cidr_ip4(spf_response, &mask, p);
749 if (err)
750 return err;
751 end = p;
752 }
753 mech->mech_len = mask;
754
755 len = end - start;
756 if ( len > sizeof( buf ) - 1 )
757 return SPF_E_INVALID_IP4;
758
759 memcpy( buf, start, len );
760 buf[ len ] = '\0';
761 addr = SPF_mech_ip4_data(mech);
762 err = inet_pton( AF_INET, buf, addr );
763 if ( err <= 0 )
765 NULL, buf, NULL);
766
767 return SPF_E_SUCCESS;
768}
769
775static SPF_errcode_t
776SPF_c_parse_ip6(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
777{
778 const char *end;
779 const char *p;
780
781 char buf[ INET6_ADDRSTRLEN ];
782 size_t len;
783 int err;
784
785 unsigned char mask;
786 struct in6_addr *addr;
787
788 start++;
789 len = strcspn(start, " ");
790 end = start + len;
791 p = end - 1;
792
793 mask = 0;
794 while (isdigit( (unsigned char)(*p) ))
795 p--;
796 if (p != (end - 1) && *p == '/') {
797 err = SPF_c_parse_cidr_ip6(spf_response, &mask, p);
798 if (err)
799 return err;
800 end = p;
801 }
802 mech->mech_len = mask;
803
804 len = end - start;
805 if ( len > sizeof( buf ) - 1 )
806 return SPF_E_INVALID_IP6;
807
808 memcpy( buf, start, len );
809 buf[ len ] = '\0';
810 addr = SPF_mech_ip6_data(mech);
811 err = inet_pton( AF_INET6, buf, addr );
812 if ( err <= 0 )
814 NULL, buf, NULL);
815
816 return SPF_E_SUCCESS;
817}
818
819
820/* XXX TODO: Make this take (const char *) instead of (const char **)
821 * because the caller ignores the modified value. */
822__attribute__((warn_unused_result))
823static SPF_errcode_t
824SPF_c_mech_add(SPF_server_t *spf_server,
825 SPF_record_t *spf_record, SPF_response_t *spf_response,
826 const SPF_mechtype_t *mechtype, int prefix,
827 const char **mech_value)
828{
829 /* If this buffer is an irregular size, intel gcc does not align
830 * it properly, and all hell breaks loose. */
832 char buf[SPF_RECORD_BUFSIZ];
833);
834 SPF_mech_t *spf_mechanism = (SPF_mech_t *)ALIGNED_DECL(buf);
835 SPF_data_t *data;
836 size_t data_len;
837 size_t len;
838 size_t src_len;
839
840 SPF_errcode_t err;
841
842 memset(u.buf, 'B', sizeof(u.buf)); /* Poison the buffer. */
843 memset(spf_mechanism, 0, sizeof(SPF_mech_t));
844
845 if (spf_server->debug)
846 SPF_debugf("SPF_c_mech_add: type=%d, value=%s",
847 mechtype->mech_type, *mech_value);
848
849 spf_mechanism->prefix_type = prefix;
850 spf_mechanism->mech_type = mechtype->mech_type;
851 spf_mechanism->mech_len = 0;
852
853 len = sizeof( SPF_mech_t );
854
855 if ( spf_record->mech_len + len > SPF_MAX_MECH_LEN )
856 return SPF_E_BIG_MECH;
857
858 data = SPF_mech_data(spf_mechanism);
859 data_len = 0;
860
861 src_len = strcspn(*mech_value, " ");
862
863 switch (mechtype->mech_type) {
864 /* We know the properties of IP4 and IP6. */
865 case MECH_IP4:
866 if (**mech_value == ':') {
867 err = SPF_c_parse_ip4(spf_response, spf_mechanism, *mech_value);
868 data_len = sizeof(struct in_addr);
869 }
870 else {
871 err = SPF_E_MISSING_OPT;
872 SPF_response_add_error_ptr(spf_response, err,
873 NULL, *mech_value,
874 "Mechanism requires a value.");
875 }
876 break;
877
878 case MECH_IP6:
879 if (**mech_value == ':') {
880 err = SPF_c_parse_ip6(spf_response, spf_mechanism, *mech_value);
881 data_len = sizeof(struct in6_addr);
882 }
883 else {
884 err = SPF_E_MISSING_OPT;
885 SPF_response_add_error_ptr(spf_response, err,
886 NULL, *mech_value,
887 "Mechanism requires a value.");
888 }
889 break;
890
891 default:
892 if (**mech_value == ':' || **mech_value == '=') {
893 if (mechtype->has_domainspec == DOMSPEC_NONE) {
894 err = SPF_E_INVALID_OPT;
895 SPF_response_add_error_ptr(spf_response, err,
896 NULL, *mech_value,
897 "Mechanism does not permit a value.");
898 }
899 else {
900 (*mech_value)++; src_len--;
901 err = SPF_c_parse_domainspec(spf_server,
902 spf_response,
903 data, &data_len, SPF_MAX_MECH_LEN,
904 *mech_value, src_len,
906 mechtype->has_cidr, FALSE);
907 }
908 }
909 else if (**mech_value == '/') {
910 if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
911 err = SPF_E_MISSING_OPT;
912 SPF_response_add_error_ptr(spf_response, err,
913 NULL, *mech_value,
914 "Mechanism requires a value.");
915 }
916 else if (mechtype->has_cidr == CIDR_NONE) {
917 err = SPF_E_INVALID_CIDR;
918 SPF_response_add_error_ptr(spf_response, err,
919 NULL, *mech_value,
920 "Mechanism does not permit a CIDR.");
921 }
922 else {
923 err = SPF_c_parse_domainspec(spf_server,
924 spf_response,
925 data, &data_len, SPF_MAX_MECH_LEN,
926 *mech_value, src_len,
929 }
930 }
931 else if (**mech_value == ' ' || **mech_value == '\0') {
932 if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
933 err = SPF_E_MISSING_OPT;
934 SPF_response_add_error_ptr(spf_response, err,
935 NULL, *mech_value,
936 "Mechanism requires a value.");
937 }
938 else {
939 err = SPF_E_SUCCESS;
940 }
941 }
942 else {
943 err = SPF_E_SYNTAX;
944 SPF_response_add_error_ptr(spf_response, err,
945 NULL, *mech_value,
946 "Unknown character '%c' after mechanism.",
947 **mech_value);
948 }
949
950 /* Does not apply to ip4/ip6 */
951 spf_mechanism->mech_len = data_len;
952 break;
953 }
954
955 len += data_len;
956
957 /* Copy the thing in. */
958 if (err == SPF_E_SUCCESS) {
959 if (mechtype->is_dns_mech)
960 spf_record->num_dns_mech++;
961 if (SPF_c_ensure_capacity((void **)&spf_record->mech_first,
962 &spf_record->mech_size,
963 spf_record->mech_len + len) < 0)
964 return SPF_response_add_error_ptr(spf_response,
966 NULL, NULL,
967 "Failed to allocate memory for mechanism");
968 memcpy( (char *)spf_record->mech_first + spf_record->mech_len,
969 spf_mechanism,
970 len);
971 spf_record->mech_len += len;
972 spf_record->num_mech++;
973 }
974
975 *mech_value += src_len;
976
977 return err;
978}
979
980__attribute__((warn_unused_result))
981static SPF_errcode_t
982SPF_c_mod_add(SPF_server_t *spf_server,
983 SPF_record_t *spf_record, SPF_response_t *spf_response,
984 const char *mod_name, size_t name_len,
985 const char **mod_value)
986{
987 /* If this buffer is an irregular size, intel gcc does not align
988 * it properly, and all hell breaks loose. */
990 char buf[SPF_RECORD_BUFSIZ];
991);
992 SPF_mod_t *spf_modifier = (SPF_mod_t *)u.buf;
993 SPF_data_t *data;
994 size_t data_len;
995 size_t len;
996 size_t src_len;
997
998 SPF_errcode_t err;
999
1000 if (spf_server->debug)
1001 SPF_debugf("Adding modifier name=%lu@%s, value=%s",
1002 (unsigned long)name_len, mod_name, *mod_value);
1003
1004 memset(u.buf, 'A', sizeof(u.buf));
1005 memset(spf_modifier, 0, sizeof(SPF_mod_t));
1006
1007 if ( name_len > SPF_MAX_MOD_LEN )
1008 return SPF_E_BIG_MOD;
1009
1010 spf_modifier->name_len = name_len;
1011 spf_modifier->data_len = 0;
1012
1013 /* So that spf_modifier + len == SPF_mod_data(spf_modifier) */
1014 len = _align_sz(sizeof( SPF_mod_t ) + name_len);
1015
1016 if ( spf_record->mod_len + len > SPF_MAX_MOD_LEN )
1017 return SPF_E_BIG_MOD;
1018
1019 memcpy(SPF_mod_name(spf_modifier), mod_name, name_len);
1020
1021 data = SPF_mod_data(spf_modifier);
1022 data_len = 0;
1023
1024 src_len = strcspn(*mod_value, " ");
1025
1026 err = SPF_c_parse_macro(spf_server,
1027 spf_response,
1028 data, &data_len, SPF_MAX_MOD_LEN,
1029 *mod_value, src_len,
1031 TRUE );
1032 spf_modifier->data_len = data_len;
1033 len += data_len;
1034
1035 /* Copy the thing in. */
1036 if (err == SPF_E_SUCCESS) {
1037 if (SPF_c_ensure_capacity((void **)&spf_record->mod_first,
1038 &spf_record->mod_size,
1039 spf_record->mod_len + len) < 0)
1040 return SPF_response_add_error_ptr(spf_response,
1042 NULL, NULL,
1043 "Failed to allocate memory for modifier");
1044 memcpy( (char *)spf_record->mod_first + spf_record->mod_len,
1045 spf_modifier,
1046 len);
1047 spf_record->mod_len += len;
1048 spf_record->num_mod++;
1049 }
1050
1051 return err;
1052}
1053
1054static void
1055SPF_record_lint(SPF_server_t *spf_server,
1056 SPF_response_t *spf_response,
1057 SPF_record_t *spf_record)
1058{
1059 SPF_data_t *d, *data_end;
1060
1061 char *s;
1062 char *s_end;
1063
1064 int found_non_ip;
1065 int found_valid_tld;
1066
1067 SPF_mech_t *mech;
1068 SPF_data_t *data;
1069
1070 int i;
1071
1072 /* FIXME these warnings suck. Should call SPF_id2str to give more
1073 * context. */
1074
1075 mech = spf_record->mech_first;
1076 for (i = 0;
1077 i < spf_record->num_mech;
1078 i++,
1079 mech = SPF_mech_next( mech ) )
1080 {
1081 if ( ( mech->mech_type == MECH_ALL
1082 || mech->mech_type == MECH_REDIRECT )
1083 && i != spf_record->num_mech - 1 )
1084 {
1086 "Mechanisms found after the \"all:\" "
1087 "mechanism will be ignored.");
1088 }
1089
1090 /*
1091 * if we are dealing with a mechanism, make sure that the data
1092 * at least looks like a valid host name.
1093 *
1094 * note: this routine isn't called to handle ip4: and ip6: and all
1095 * the other mechanisms require a host name.
1096 */
1097
1098 if ( mech->mech_type == MECH_IP4
1099 || mech->mech_type == MECH_IP6 )
1100 continue;
1101
1102 data = SPF_mech_data( mech );
1103 data_end = SPF_mech_end_data( mech );
1104 if ( data == data_end )
1105 continue;
1106
1107 if ( data->dc.parm_type == PARM_CIDR )
1108 {
1109 data = SPF_data_next( data );
1110 if ( data == data_end )
1111 continue;
1112 }
1113
1114
1115 found_valid_tld = FALSE;
1116 found_non_ip = FALSE;
1117
1118 for( d = data; d < data_end; d = SPF_data_next( d ) )
1119 {
1120 switch( d->dv.parm_type )
1121 {
1122 case PARM_CIDR:
1123 SPF_error( "Multiple CIDR parameters found" );
1124 break;
1125
1126 case PARM_CLIENT_IP:
1127 case PARM_CLIENT_IP_P:
1128 case PARM_LP_FROM:
1129 found_valid_tld = FALSE;
1130 break;
1131
1132 case PARM_STRING:
1133 found_valid_tld = FALSE;
1134
1135 s = SPF_data_str( d );
1136 s_end = s + d->ds.len;
1137 for( ; s < s_end; s++ ) {
1138 if ( !isdigit( (unsigned char)( *s ) ) && *s != '.' && *s != ':' )
1139 found_non_ip = TRUE;
1140
1141 if ( *s == '.' )
1142 found_valid_tld = TRUE;
1143 else if ( !isalpha( (unsigned char)( *s ) ) )
1144 found_valid_tld = FALSE;
1145 }
1146 break;
1147
1148 default:
1149 found_non_ip = TRUE;
1150 found_valid_tld = TRUE;
1151
1152 break;
1153 }
1154 }
1155
1156 if ( !found_valid_tld || !found_non_ip ) {
1157 if ( !found_non_ip )
1159 "Invalid hostname (an IP address?)");
1160 else if ( !found_valid_tld )
1162 "Hostname has a missing or invalid TLD");
1163 }
1164
1165 }
1166
1167 /* FIXME check for modifiers that should probably be mechanisms */
1168}
1169
1170
1171
1180SPF_record_compile(SPF_server_t *spf_server,
1181 SPF_response_t *spf_response,
1182 SPF_record_t **spf_recordp,
1183 const char *record)
1184{
1185 const SPF_mechtype_t*mechtype;
1186 SPF_record_t *spf_record;
1187 SPF_error_t *spf_error;
1188 SPF_errcode_t err;
1189
1190 const char *name_start;
1191 size_t name_len;
1192
1193 const char *val_start;
1194 const char *val_end;
1195
1196 int prefix;
1197
1198 const char *p;
1199 int i;
1200
1201
1202 /*
1203 * make sure we were passed valid data to work with
1204 */
1205 SPF_ASSERT_NOTNULL(spf_server);
1206 SPF_ASSERT_NOTNULL(spf_recordp);
1207 SPF_ASSERT_NOTNULL(record);
1208
1209 if (spf_server->debug)
1210 SPF_debugf("Compiling record %s", record);
1211
1212 /*
1213 * and make sure that we will always set *spf_recordp
1214 * just incase we can't find a valid SPF record
1215 */
1216 *spf_recordp = NULL;
1217
1218 /*
1219 * See if this is record is even an SPF record
1220 */
1221 p = record;
1222
1223 if (strncasecmp(p, SPF_VER_STR, sizeof(SPF_VER_STR) - 1) != 0)
1224 return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1225 NULL, p,
1226 "Could not find a valid SPF record");
1227 p += sizeof( SPF_VER_STR ) - 1;
1228
1229 if ( *p != '\0' && *p != ' ' )
1230 return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1231 NULL, p,
1232 "Could not find a valid SPF record");
1233
1234 spf_record = SPF_record_new(spf_server, record);
1235 if (spf_record == NULL) {
1236 *spf_recordp = NULL;
1237 return SPF_response_add_error_ptr(spf_response, SPF_E_NO_MEMORY,
1238 NULL, p,
1239 "Failed to allocate an SPF record");
1240 }
1241 spf_record->version = 1;
1242 *spf_recordp = spf_record;
1243
1244 /*
1245 * parse the SPF record
1246 */
1247 while (*p != '\0') {
1248 /* TODO WARN: If it's a \n or a \t */
1249 /* skip to the next token */
1250 while (*p == ' ')
1251 p++;
1252
1253 if (*p == '\0')
1254 break;
1255
1256 /* see if we have a valid prefix */
1257 prefix = PREFIX_UNKNOWN;
1258 switch (*p) {
1259 case '+':
1260 prefix = PREFIX_PASS;
1261 p++;
1262 break;
1263
1264 case '-':
1265 prefix = PREFIX_FAIL;
1266 p++;
1267 break;
1268
1269 case '~':
1270 prefix = PREFIX_SOFTFAIL;
1271 p++;
1272 break;
1273
1274 case '?':
1275 prefix = PREFIX_NEUTRAL;
1276 p++;
1277 break;
1278
1279 default:
1280 while (ispunct((unsigned char)(*p))) {
1281 SPF_response_add_error_ptr(spf_response,
1283 "Invalid prefix '%c'", *p);
1284 p++;
1285 }
1286 break;
1287 }
1288
1289 name_start = p;
1290 val_end = name_start + strcspn(p, " ");
1291
1292 /* get the mechanism/modifier */
1293 if ( ! isalpha( (unsigned char)*p ) ) {
1294 /* We could just bail on this one. */
1295 SPF_response_add_error_ptr(spf_response,
1297 "Invalid character at start of mechanism");
1298 p += strcspn(p, " ");
1299 continue;
1300 }
1301 while ( isalnum( (unsigned char)*p ) || *p == '_' || *p == '-' )
1302 p++;
1303
1304/* TODO: These or macros like them are used in several places. Merge. */
1305#define STREQ_SIZEOF(a, b) \
1306 (strncasecmp((a), (b), sizeof( (b) ) - 1) == 0)
1307#define STREQ_SIZEOF_N(a, b, n) \
1308 (((n) == sizeof(b) - 1) && (strncasecmp((a),(b),(n)) == 0))
1309
1310 /* See if we have a modifier or a prefix */
1311 name_len = p - name_start;
1312
1313 if (spf_server->debug)
1314 SPF_debugf("Name starts at %s", name_start);
1315
1316 switch ( *p )
1317 {
1318 case ':':
1319 case '/':
1320 case ' ':
1321 case '\0':
1322 compile_mech: /* A bona fide label */
1323
1324 /*
1325 * parse the mechanism
1326 */
1327
1328 /* mechanisms default to PREFIX_PASS */
1329 if ( prefix == PREFIX_UNKNOWN )
1330 prefix = PREFIX_PASS;
1331
1332 if ( STREQ_SIZEOF_N(name_start, "a", name_len) )
1333 mechtype = SPF_mechtype_find(MECH_A);
1334 else if ( STREQ_SIZEOF_N(name_start, "mx", name_len) )
1335 mechtype = SPF_mechtype_find(MECH_MX);
1336 else if ( STREQ_SIZEOF_N(name_start, "ptr", name_len) )
1337 mechtype = SPF_mechtype_find(MECH_PTR);
1338 else if ( STREQ_SIZEOF_N(name_start, "include", name_len) )
1339 mechtype = SPF_mechtype_find(MECH_INCLUDE);
1340 else if ( STREQ_SIZEOF_N(name_start, "ip4", name_len) )
1341 mechtype = SPF_mechtype_find(MECH_IP4);
1342 else if ( STREQ_SIZEOF_N(name_start, "ip6", name_len) )
1343 mechtype = SPF_mechtype_find(MECH_IP6);
1344 else if ( STREQ_SIZEOF_N(name_start, "exists", name_len) )
1345 mechtype = SPF_mechtype_find(MECH_EXISTS);
1346 else if ( STREQ_SIZEOF_N(name_start, "all", name_len) )
1347 mechtype = SPF_mechtype_find(MECH_ALL);
1348#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1349 else if ( STREQ_SIZEOF_N(name_start,
1350 "default=allow", name_len) )
1351 {
1353 NULL, name_start,
1354 "Deprecated option 'default=allow'");
1355 mechtype = SPF_mechtype_find(MECH_ALL);
1356 prefix = PREFIX_PASS;
1357 }
1358 else if (STREQ_SIZEOF_N(name_start,
1359 "default=softfail",name_len))
1360 {
1362 NULL, name_start,
1363 "Deprecated option 'default=softfail'");
1364 mechtype = SPF_mechtype_find(MECH_ALL);
1365 prefix = PREFIX_SOFTFAIL;
1366 }
1367 else if ( STREQ_SIZEOF_N(name_start,
1368 "default=deny", name_len) )
1369 {
1371 NULL, name_start,
1372 "Deprecated option 'default=deny'");
1373 mechtype = SPF_mechtype_find(MECH_ALL);
1374 prefix = PREFIX_FAIL;
1375 }
1376 else if ( STREQ_SIZEOF(name_start, "default=") )
1377 {
1379 NULL, name_start,
1380 "Invalid modifier 'default=...'");
1381 p = val_end;
1382 continue;
1383 }
1384#endif
1385 /* FIXME the redirect mechanism needs to be moved to
1386 * the very end */
1387 else if ( STREQ_SIZEOF_N(name_start, "redirect", name_len) )
1388 mechtype = SPF_mechtype_find(MECH_REDIRECT);
1389 else
1390 {
1392 NULL, name_start,
1393 "Unknown mechanism found");
1394 p = val_end;
1395 continue;
1396 }
1397
1398 if (mechtype == NULL) {
1399 return SPF_response_add_error_ptr(spf_response,
1401 NULL, name_start,
1402 "Failed to find specification for "
1403 "a recognised mechanism");
1404 }
1405
1406 if (spf_server->debug)
1407 SPF_debugf("Adding mechanism type %d",
1408 (int)mechtype->mech_type);
1409
1410 val_start = p;
1411 err = SPF_c_mech_add(spf_server,
1412 spf_record, spf_response,
1413 mechtype, prefix, &val_start);
1414 if (err == SPF_E_NO_MEMORY)
1415 return err;
1416 /* XXX Else do nothing. Continue for the next error. */
1417 /* We shouldn't have to worry about the child function
1418 * updating the pointer. So we just use our 'well known'
1419 * copy. */
1420 p = val_end;
1421 break;
1422
1423 case '=':
1424
1425 /*
1426 * parse the modifier
1427 */
1428
1429 /* modifiers can't have prefixes */
1430 if (prefix != PREFIX_UNKNOWN)
1432 NULL, name_start,
1433 "Modifiers may not have prefixes");
1434 prefix = PREFIX_UNKNOWN; /* For redirect/include */
1435
1436#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1437 /* Deal with legacy special case */
1438 if ( STREQ_SIZEOF(name_start, "default=") ) {
1439 /* Consider the whole 'default=foo' as a token. */
1440 p = val_end;
1441 name_len = p - name_start;
1442 goto compile_mech;
1443 }
1444#endif
1445
1446 /* We treat 'redirect' as a mechanism. */
1447 if ( STREQ_SIZEOF(name_start, "redirect=") )
1448 goto compile_mech;
1449
1450 p++;
1451 val_start = p;
1452 err = SPF_c_mod_add(spf_server,
1453 spf_record, spf_response,
1454 name_start, name_len, &val_start);
1455 if (err == SPF_E_NO_MEMORY)
1456 return err;
1457 /* XXX Else do nothing. Continue for the next error. */
1458 p = val_end;
1459 break;
1460
1461
1462 default:
1464 NULL, p,
1465 "Invalid character in middle of mechanism");
1466 p = val_end;
1467 break;
1468 }
1469 }
1470
1471
1472 /*
1473 * check for common mistakes
1474 */
1475 SPF_record_lint(spf_server, spf_response, spf_record);
1476
1477
1478 /*
1479 * do final cleanup on the record
1480 */
1481
1482 /* FIXME realloc (shrink) spfi buffers? */
1483
1484 if (SPF_response_errors(spf_response) > 0) {
1485 for (i = 0; i < SPF_response_messages(spf_response); i++) {
1486 spf_error = SPF_response_message(spf_response, i);
1487 if (SPF_error_errorp(spf_error))
1488 return SPF_error_code(spf_error);
1489 }
1490 return SPF_response_add_error(spf_response,
1492 "Response has errors but can't find one!");
1493 }
1494
1495 return SPF_E_SUCCESS;
1496}
1497
1499SPF_record_compile_macro(SPF_server_t *spf_server,
1500 SPF_response_t *spf_response,
1501 SPF_macro_t **spf_macrop,
1502 const char *record)
1503{
1505 char buf[sizeof(SPF_macro_t) + SPF_MAX_MOD_LEN];
1506);
1507 SPF_macro_t *spf_macro = (SPF_macro_t *)ALIGNED_DECL(buf);
1508 SPF_data_t *data;
1509 SPF_errcode_t err;
1510 size_t size;
1511
1512 data = SPF_macro_data(spf_macro);
1513 spf_macro->macro_len = 0;
1514
1515 err = SPF_c_parse_macro(spf_server, spf_response,
1516 data, &spf_macro->macro_len, SPF_MAX_MOD_LEN,
1517 record, strlen(record),
1519 if (err != SPF_E_SUCCESS)
1520 return err;
1521
1522 /* XXX TODO: Tidy this up? */
1523 size = sizeof(SPF_macro_t) + spf_macro->macro_len;
1524 *spf_macrop = (SPF_macro_t *)malloc(size);
1525 if (!*spf_macrop)
1526 return SPF_E_NO_MEMORY;
1527 memcpy(*spf_macrop, ALIGNED_DECL(buf), size);
1528
1529 return SPF_E_SUCCESS;
1530}
#define SPF_ENSURE_STRING_AVAIL(_len)
Definition: spf_compile.c:462
#define SPF_RECORD_BUFSIZ
Definition: spf_compile.c:62
#define ALIGN_DECL(decl)
Definition: spf_compile.c:64
#define STREQ_SIZEOF(a, b)
#define SPF_ADD_LEN_TO(_val, _len, _max)
Definition: spf_compile.c:441
SPF_domspec_t
Definition: spf_compile.c:53
@ DOMSPEC_REQUIRED
Definition: spf_compile.c:54
@ DOMSPEC_OPTIONAL
Definition: spf_compile.c:54
@ DOMSPEC_NONE
Definition: spf_compile.c:54
#define SPF_FINI_STRING_LITERAL()
Definition: spf_compile.c:471
SPF_cidr_t
Definition: spf_compile.c:48
@ CIDR_ONLY
Definition: spf_compile.c:49
@ CIDR_NONE
Definition: spf_compile.c:49
@ CIDR_OPTIONAL
Definition: spf_compile.c:49
SPF_errcode_t SPF_record_compile(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_record_t **spf_recordp, const char *record)
Definition: spf_compile.c:1180
#define ALIGNED_DECL(var)
Definition: spf_compile.c:65
#define STREQ_SIZEOF_N(a, b, n)
#define SPF_INIT_STRING_LITERAL(_avail)
Definition: spf_compile.c:452
#define SPF_CHECK_IN_MODIFIER()
#define spf_num_mechanisms
Definition: spf_compile.c:91
SPF_errcode_t SPF_record_compile_macro(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_macro_t **spf_macrop, const char *record)
Definition: spf_compile.c:1499
int strncasecmp(const char *s1, const char *s2, size_t n)
Definition: strncasecmp.c:11
SPF_errcode_t SPF_response_add_warn_ptr(SPF_response_t *rp, SPF_errcode_t code, const char *text, const char *tptr, const char *format,...)
Definition: spf_response.c:264
SPF_errcode_t SPF_response_add_error_ptr(SPF_response_t *rp, SPF_errcode_t code, const char *text, const char *tptr, const char *format,...)
Definition: spf_response.c:238
SPF_errcode_t SPF_response_add_warn(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:282
SPF_errcode_t SPF_response_add_error(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:256
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
Definition: spf_response.c:308
int SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
char SPF_error_errorp(SPF_error_t *err)
Definition: spf_response.c:326
SPF_errcode_t SPF_error_code(SPF_error_t *err)
Definition: spf_response.c:314
SPF_errcode_t
Definition: spf_response.h:119
@ SPF_E_MECH_AFTER_ALL
Definition: spf_response.h:149
@ SPF_E_MOD_W_PREF
Definition: spf_response.h:124
@ SPF_E_UNKNOWN_MECH
Definition: spf_response.h:126
@ SPF_E_INVALID_CHAR
Definition: spf_response.h:125
@ SPF_E_SYNTAX
Definition: spf_response.h:123
@ SPF_E_INVALID_IP6
Definition: spf_response.h:140
@ SPF_E_INTERNAL_ERROR
Definition: spf_response.h:130
@ SPF_E_INVALID_OPT
Definition: spf_response.h:127
@ SPF_E_BAD_HOST_TLD
Definition: spf_response.h:148
@ SPF_E_NO_MEMORY
Definition: spf_response.h:121
@ SPF_E_BAD_HOST_IP
Definition: spf_response.h:147
@ SPF_E_INVALID_VAR
Definition: spf_response.h:132
@ SPF_E_BIG_SUBDOM
Definition: spf_response.h:133
@ SPF_E_NOT_SPF
Definition: spf_response.h:122
@ SPF_E_INVALID_DELIM
Definition: spf_response.h:134
@ SPF_E_MISSING_OPT
Definition: spf_response.h:129
@ SPF_E_INVALID_IP4
Definition: spf_response.h:139
@ SPF_E_BIG_MECH
Definition: spf_response.h:136
@ SPF_E_INVALID_CIDR
Definition: spf_response.h:128
@ SPF_E_SUCCESS
Definition: spf_response.h:120
@ SPF_E_INVALID_PREFIX
Definition: spf_response.h:141
@ SPF_E_BIG_MOD
Definition: spf_response.h:137
int SPF_response_errors(SPF_response_t *rp)
Definition: spf_response.c:296
#define PARM_LP_FROM
Definition: spf_record.h:88
#define PARM_CUR_DOM
Definition: spf_record.h:91
#define MECH_EXISTS
Definition: spf_record.h:169
#define PREFIX_PASS
Definition: spf_record.h:153
#define PARM_CLIENT_VER
Definition: spf_record.h:96
#define PARM_REC_DOM
Definition: spf_record.h:98
#define MECH_REDIRECT
Definition: spf_record.h:171
#define PARM_STRING
Definition: spf_record.h:100
#define PREFIX_NEUTRAL
Definition: spf_record.h:156
#define MECH_INCLUDE
Definition: spf_record.h:166
#define PARM_HELO_DOM
Definition: spf_record.h:97
#define PARM_CLIENT_IP_P
Definition: spf_record.h:93
#define MECH_IP6
Definition: spf_record.h:168
#define PARM_CIDR
Definition: spf_record.h:99
#define MECH_IP4
Definition: spf_record.h:167
#define PARM_CLIENT_DOM
Definition: spf_record.h:95
#define MECH_MX
Definition: spf_record.h:164
#define MECH_PTR
Definition: spf_record.h:165
#define PARM_ENV_FROM
Definition: spf_record.h:89
#define PREFIX_UNKNOWN
Definition: spf_record.h:157
#define SPF_MAX_MOD_LEN
Definition: spf_record.h:78
#define MECH_ALL
Definition: spf_record.h:170
#define MECH_UNKNOWN
Definition: spf_record.h:162
#define SPF_MAX_MECH_LEN
Definition: spf_record.h:77
#define MECH_A
Definition: spf_record.h:163
#define PARM_TIME
Definition: spf_record.h:94
#define PARM_CLIENT_IP
Definition: spf_record.h:92
#define PARM_DP_FROM
Definition: spf_record.h:90
#define PREFIX_SOFTFAIL
Definition: spf_record.h:155
SPF_record_t * SPF_record_new(SPF_server_t *spf_server, const char *text)
Definition: spf_record.c:48
#define PREFIX_FAIL
Definition: spf_record.h:154
#define SPF_errorf
Definition: spf_log.h:77
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
#define SPF_error(errmsg)
Definition: spf_log.h:40
#define SPF_debugf
Definition: spf_log.h:80
#define NULL
Definition: spf_internal.h:28
#define TRUE
Definition: spf_internal.h:23
#define FALSE
Definition: spf_internal.h:24
#define SPF_VER_STR
Definition: spf.h:35
#define __attribute__(x)
Definition: spf.h:17
unsigned char len
Definition: spf_record.h:107
unsigned short rev
Definition: spf_record.h:119
unsigned short delim_under
Definition: spf_record.h:126
unsigned short delim_dot
Definition: spf_record.h:121
unsigned char num_rhs
Definition: spf_record.h:118
unsigned short delim_bar
Definition: spf_record.h:125
unsigned char parm_type
Definition: spf_record.h:117
unsigned short delim_dash
Definition: spf_record.h:122
unsigned short delim_plus
Definition: spf_record.h:123
unsigned short delim_equal
Definition: spf_record.h:124
unsigned short url_encode
Definition: spf_record.h:120
unsigned char ipv6
Definition: spf_record.h:134
unsigned char ipv4
Definition: spf_record.h:133
unsigned char parm_type
Definition: spf_record.h:132
SPF_data_str_t ds
Definition: spf_record.h:144
SPF_data_cidr_t dc
Definition: spf_record.h:145
SPF_data_var_t dv
Definition: spf_record.h:143
unsigned short mech_len
Definition: spf_record.h:178
SPF_cidr_t has_cidr
Definition: spf_compile.c:75
unsigned char mech_type
Definition: spf_compile.c:72
unsigned char is_dns_mech
Definition: spf_compile.c:73
SPF_domspec_t has_domainspec
Definition: spf_compile.c:74