40#undef SPF_ALLOW_DEPRECATED_DEFAULT
53enum SPF_domspec_enum {
62#define SPF_RECORD_BUFSIZ 4096
64#define ALIGN_DECL(decl) union { double d; long l; decl } __attribute__((aligned(_ALIGN_SZ))) u
65#define ALIGNED_DECL(var) u.var
70struct SPF_mechtype_struct
91#define spf_num_mechanisms \
92 sizeof(spf_mechtypes) / sizeof(spf_mechtypes[0])
95SPF_mechtype_find(
int mech_type)
99 if (spf_mechtypes[i].mech_type == mech_type)
100 return &spf_mechtypes[i];
107SPF_c_ensure_capacity(
void **datap,
size_t *sizep,
size_t length)
109 size_t size = *sizep;
111 size = length + (length / 4);
113 void *tmp = realloc(*datap, size);
133SPF_c_parse_cidr_ip6(SPF_response_t *spf_response,
134 unsigned char *maskp,
144 mask = strtoul(src + 1,
NULL, 10);
149 "Invalid IPv6 CIDR netmask (>128)");
151 else if (mask == 0) {
154 "Invalid IPv6 CIDR netmask (=0)");
156 else if (mask == 128) {
175SPF_c_parse_cidr_ip4(SPF_response_t *spf_response,
176 unsigned char *maskp,
186 mask = strtoul(src + 1,
NULL, 10);
191 "Invalid IPv4 CIDR netmask (>32)");
193 else if ( mask == 0 ) {
196 "Invalid IPv4 CIDR netmask (=0)");
198 else if ( mask == 32 ) {
213SPF_c_parse_cidr(SPF_response_t *spf_response,
215 const char *src,
size_t *src_len)
228 while (idx > 0 && isdigit( (
unsigned char)(src[idx]) ))
236 if (idx < (*src_len - 1) && src[idx] ==
'/') {
237 if (idx > 0 && src[idx - 1] ==
'/') {
239 err = SPF_c_parse_cidr_ip6(spf_response, &data->
ipv6, &src[idx]);
245 while (idx > 0 && isdigit( (
unsigned char)(src[idx]) ))
249 if (idx < (*src_len - 1) && src[idx] ==
'/') {
253 err = SPF_c_parse_cidr_ip4(spf_response, &data->
ipv4, &src[idx]);
261 err = SPF_c_parse_cidr_ip4(spf_response, &data->
ipv4, &src[idx]);
272SPF_c_parse_var(SPF_response_t *spf_response,
SPF_data_var_t *data,
273 const char *src,
int is_mod)
286 if ( isupper( (
unsigned char)( c ) ) )
294#define SPF_CHECK_IN_MODIFIER() \
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);
352 "Unknown variable '%c'", c);
359 while ( isdigit( (
unsigned char)( *p ) ) )
365 if ( val > 128 || (val <= 0 && p != token) )
368 "Subdomain truncation depth too large");
428 "Invalid delimiter '%c'", *p);
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); \
449 (_val) += _align_sz(_len); \
452#define SPF_INIT_STRING_LITERAL(_avail) do { \
453 data->ds.parm_type = PARM_STRING; \
456 data->ds.__unused0 = 0xba; data->ds.__unused1 = 0xbe; \
457 dst = SPF_data_str( data ); \
458 if ((_avail) < sizeof(SPF_data_t)) \
459 return SPF_response_add_error_ptr(spf_response, \
460 SPF_E_BIG_STRING, NULL, src, \
461 "Out of memory for string literal");\
462 ds_avail = (_avail) - sizeof(SPF_data_t); \
466#define SPF_ENSURE_STRING_AVAIL(_len) do { \
467 if (ds_len + _len > ds_avail) \
468 return SPF_response_add_error_ptr(spf_response, \
469 SPF_E_BIG_STRING, NULL, src, \
470 "String literal fragment too long " \
471 "(%d chars, %d max)", \
475#define SPF_FINI_STRING_LITERAL() do { \
476 if ( ds_len > 0 ) { \
477 if ( ds_len > SPF_MAX_STR_LEN ) { \
478 return SPF_response_add_error_ptr(spf_response, \
479 SPF_E_BIG_STRING, NULL, src, \
480 "String literal too long " \
481 "(%d chars, %d max)", \
482 ds_len, SPF_MAX_STR_LEN); \
484 data->ds.len = ds_len; \
485 len = sizeof( *data ) + ds_len; \
486 SPF_ADD_LEN_TO(*data_used, len, data_avail); \
487 data = SPF_data_next( data ); \
510SPF_c_parse_macro(SPF_server_t *spf_server,
511 SPF_response_t *spf_response,
512 SPF_data_t *data,
size_t *data_used,
size_t data_avail,
513 const char *src,
size_t src_len,
526 if (spf_server->debug)
527 SPF_debugf(
"Parsing macro starting at %s", src);
530 if ((
void *)data != _align_ptr((
void *)data))
531 SPF_errorf(
"Data pointer %p is not aligned: Cannot compile.",
545 while (idx < src_len) {
546 if (spf_server->debug > 3)
550 len = strcspn(&src[idx],
" %");
553 if (idx + len > src_len)
555 if (spf_server->debug > 3)
556 SPF_debugf(
"Adding string literal (%lu): '%*.*s'",
558 (
int)len, (
int)len, &src[idx]);
561 memcpy(dst, &src[idx], len);
583 if (spf_server->debug > 3)
592 if (spf_server->debug > 3)
601 if (spf_server->debug > 3)
604 *dst++ =
'%'; *dst++ =
'2'; *dst++ =
'0';
610 if (spf_server->debug > 3)
611 SPF_debugf(
"Adding illegal %%-follower '%c' at %zu",
623 if (spf_server->debug > 3)
624 SPF_debugf(
"Adding macro, data is at %p", data);
628 err = SPF_c_parse_var(spf_response, &data->
dv, &src[idx], is_mod);
631 idx += strcspn(&src[idx],
"} ");
634 else if (src[idx] ==
' ')
638 "Unterminated variable?");
641 len = SPF_data_len(data);
643 data = SPF_data_next( data );
644 if (spf_server->debug > 3)
675SPF_c_parse_domainspec(SPF_server_t *spf_server,
676 SPF_response_t *spf_response,
677 SPF_data_t *data,
size_t *data_used,
size_t data_avail,
678 const char *src,
size_t src_len,
686 if (spf_server->debug)
687 SPF_debugf(
"Parsing domainspec starting at %s, cidr is %s",
699 err = SPF_c_parse_cidr(spf_response, &data->
dc, src, &src_len);
703 len = SPF_data_len(data);
705 data = SPF_data_next(data);
708 if (cidr_ok ==
CIDR_ONLY && src_len > 0) {
715 "Invalid CIDR after mechanism");
719 return SPF_c_parse_macro(spf_server, spf_response,
720 data, data_used, data_avail,
721 src, src_len, big_err, is_mod);
731SPF_c_parse_ip4(SPF_response_t *spf_response,
SPF_mech_t *mech,
char const *start)
736 char buf[ INET6_ADDRSTRLEN ];
741 struct in_addr *addr;
744 len = strcspn(start,
" ");
749 while (isdigit( (
unsigned char)(*p) ))
751 if (p != (end - 1) && *p ==
'/') {
752 err = SPF_c_parse_cidr_ip4(spf_response, &mask, p);
760 if ( len >
sizeof( buf ) - 1 )
763 memcpy( buf, start, len );
765 addr = SPF_mech_ip4_data(mech);
766 err = inet_pton( AF_INET, buf, addr );
780SPF_c_parse_ip6(SPF_response_t *spf_response,
SPF_mech_t *mech,
char const *start)
785 char buf[ INET6_ADDRSTRLEN ];
790 struct in6_addr *addr;
793 len = strcspn(start,
" ");
798 while (isdigit( (
unsigned char)(*p) ))
800 if (p != (end - 1) && *p ==
'/') {
801 err = SPF_c_parse_cidr_ip6(spf_response, &mask, p);
809 if ( len >
sizeof( buf ) - 1 )
812 memcpy( buf, start, len );
814 addr = SPF_mech_ip6_data(mech);
815 err = inet_pton( AF_INET6, buf, addr );
828SPF_c_mech_add(SPF_server_t *spf_server,
829 SPF_record_t *spf_record, SPF_response_t *spf_response,
831 const char **mech_value)
846 memset(u.buf,
'B',
sizeof(u.buf));
849 if (spf_server->debug)
850 SPF_debugf(
"SPF_c_mech_add: type=%d, value=%s",
853 spf_mechanism->prefix_type = prefix;
854 spf_mechanism->mech_type = mechtype->
mech_type;
855 spf_mechanism->mech_len = 0;
862 data = SPF_mech_data(spf_mechanism);
865 src_len = strcspn(*mech_value,
" ");
870 if (**mech_value ==
':') {
871 err = SPF_c_parse_ip4(spf_response, spf_mechanism, *mech_value);
872 data_len =
sizeof(
struct in_addr);
878 "Mechanism requires a value.");
883 if (**mech_value ==
':') {
884 err = SPF_c_parse_ip6(spf_response, spf_mechanism, *mech_value);
885 data_len =
sizeof(
struct in6_addr);
891 "Mechanism requires a value.");
896 if (**mech_value ==
':' || **mech_value ==
'=') {
901 "Mechanism does not permit a value.");
904 (*mech_value)++; src_len--;
905 err = SPF_c_parse_domainspec(spf_server,
908 *mech_value, src_len,
913 else if (**mech_value ==
'/') {
918 "Mechanism requires a value.");
924 "Mechanism does not permit a CIDR.");
927 err = SPF_c_parse_domainspec(spf_server,
930 *mech_value, src_len,
935 else if (**mech_value ==
' ' || **mech_value ==
'\0') {
940 "Mechanism requires a value.");
950 "Unknown character '%c' after mechanism.",
955 spf_mechanism->mech_len = data_len;
964 spf_record->num_dns_mech++;
965 if (SPF_c_ensure_capacity((
void **)&spf_record->mech_first,
966 &spf_record->mech_size,
967 spf_record->mech_len + len) < 0)
971 "Failed to allocate memory for mechanism");
972 memcpy( (
char *)spf_record->mech_first + spf_record->mech_len,
975 spf_record->mech_len += len;
976 spf_record->num_mech++;
979 *mech_value += src_len;
986SPF_c_mod_add(SPF_server_t *spf_server,
987 SPF_record_t *spf_record, SPF_response_t *spf_response,
988 const char *mod_name,
size_t name_len,
989 const char **mod_value)
1004 if (spf_server->debug)
1005 SPF_debugf(
"Adding modifier name=%lu@%s, value=%s",
1006 (
unsigned long)name_len, mod_name, *mod_value);
1008 memset(u.buf,
'A',
sizeof(u.buf));
1009 memset(spf_modifier, 0,
sizeof(
SPF_mod_t));
1014 spf_modifier->name_len = name_len;
1015 spf_modifier->data_len = 0;
1018 len = _align_sz(
sizeof(
SPF_mod_t ) + name_len);
1023 memcpy(SPF_mod_name(spf_modifier), mod_name, name_len);
1025 data = SPF_mod_data(spf_modifier);
1028 src_len = strcspn(*mod_value,
" ");
1030 err = SPF_c_parse_macro(spf_server,
1033 *mod_value, src_len,
1036 spf_modifier->data_len = data_len;
1041 if (SPF_c_ensure_capacity((
void **)&spf_record->mod_first,
1042 &spf_record->mod_size,
1043 spf_record->mod_len + len) < 0)
1047 "Failed to allocate memory for modifier");
1048 memcpy( (
char *)spf_record->mod_first + spf_record->mod_len,
1051 spf_record->mod_len += len;
1052 spf_record->num_mod++;
1059SPF_record_lint(SPF_server_t *spf_server,
1060 SPF_response_t *spf_response,
1061 SPF_record_t *spf_record)
1069 int found_valid_tld;
1079 mech = spf_record->mech_first;
1081 i < spf_record->num_mech;
1083 mech = SPF_mech_next( mech ) )
1087 && i != spf_record->num_mech - 1 )
1090 "Mechanisms found after the \"all:\" "
1091 "mechanism will be ignored.");
1106 data = SPF_mech_data( mech );
1107 data_end = SPF_mech_end_data( mech );
1108 if ( data == data_end )
1113 data = SPF_data_next( data );
1114 if ( data == data_end )
1119 found_valid_tld =
FALSE;
1120 found_non_ip =
FALSE;
1122 for( d = data; d < data_end; d = SPF_data_next( d ) )
1127 SPF_error(
"Multiple CIDR parameters found" );
1133 found_valid_tld =
FALSE;
1137 found_valid_tld =
FALSE;
1139 s = SPF_data_str( d );
1140 s_end = s + d->
ds.
len;
1141 for( ; s < s_end; s++ ) {
1142 if ( !isdigit( (
unsigned char)( *s ) ) && *s !=
'.' && *s !=
':' )
1143 found_non_ip =
TRUE;
1146 found_valid_tld =
TRUE;
1147 else if ( !isalpha( (
unsigned char)( *s ) ) )
1148 found_valid_tld =
FALSE;
1153 found_non_ip =
TRUE;
1154 found_valid_tld =
TRUE;
1160 if ( !found_valid_tld || !found_non_ip ) {
1161 if ( !found_non_ip )
1163 "Invalid hostname (an IP address?)");
1164 else if ( !found_valid_tld )
1166 "Hostname has a missing or invalid TLD");
1185 SPF_response_t *spf_response,
1186 SPF_record_t **spf_recordp,
1190 SPF_record_t *spf_record;
1194 const char *name_start;
1197 const char *val_start;
1198 const char *val_end;
1213 if (spf_server->debug)
1220 *spf_recordp =
NULL;
1230 "Could not find a valid SPF record");
1233 if ( *p !=
'\0' && *p !=
' ' )
1236 "Could not find a valid SPF record");
1239 if (spf_record ==
NULL) {
1240 *spf_recordp =
NULL;
1243 "Failed to allocate an SPF record");
1245 spf_record->version = 1;
1246 *spf_recordp = spf_record;
1251 while (*p !=
'\0') {
1284 while (ispunct((
unsigned char)(*p))) {
1287 "Invalid prefix '%c'", *p);
1294 val_end = name_start + strcspn(p,
" ");
1297 if ( ! isalpha( (
unsigned char)*p ) ) {
1301 "Invalid character at start of mechanism");
1302 p += strcspn(p,
" ");
1305 while ( isalnum( (
unsigned char)*p ) || *p ==
'_' || *p ==
'-' )
1309#define STREQ_SIZEOF(a, b) \
1310 (strncasecmp((a), (b), sizeof( (b) ) - 1) == 0)
1311#define STREQ_SIZEOF_N(a, b, n) \
1312 (((n) == sizeof(b) - 1) && (strncasecmp((a),(b),(n)) == 0))
1315 name_len = p - name_start;
1317 if (spf_server->debug)
1337 mechtype = SPF_mechtype_find(
MECH_A);
1339 mechtype = SPF_mechtype_find(
MECH_MX);
1341 mechtype = SPF_mechtype_find(
MECH_PTR);
1345 mechtype = SPF_mechtype_find(
MECH_IP4);
1347 mechtype = SPF_mechtype_find(
MECH_IP6);
1351 mechtype = SPF_mechtype_find(
MECH_ALL);
1352#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1354 "default=allow", name_len) )
1358 "Deprecated option 'default=allow'");
1359 mechtype = SPF_mechtype_find(
MECH_ALL);
1363 "default=softfail",name_len))
1367 "Deprecated option 'default=softfail'");
1368 mechtype = SPF_mechtype_find(
MECH_ALL);
1372 "default=deny", name_len) )
1376 "Deprecated option 'default=deny'");
1377 mechtype = SPF_mechtype_find(
MECH_ALL);
1384 "Invalid modifier 'default=...'");
1397 "Unknown mechanism found");
1402 if (mechtype ==
NULL) {
1406 "Failed to find specification for "
1407 "a recognised mechanism");
1410 if (spf_server->debug)
1415 err = SPF_c_mech_add(spf_server,
1416 spf_record, spf_response,
1417 mechtype, prefix, &val_start);
1437 "Modifiers may not have prefixes");
1440#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1445 name_len = p - name_start;
1456 err = SPF_c_mod_add(spf_server,
1457 spf_record, spf_response,
1458 name_start, name_len, &val_start);
1469 "Invalid character in middle of mechanism");
1479 SPF_record_lint(spf_server, spf_response, spf_record);
1496 "Response has errors but can't find one!");
1504 SPF_response_t *spf_response,
1505 SPF_macro_t **spf_macrop,
1511 SPF_macro_t *spf_macro = (SPF_macro_t *)
ALIGNED_DECL(buf);
1516 data = SPF_macro_data(spf_macro);
1517 spf_macro->macro_len = 0;
1519 err = SPF_c_parse_macro(spf_server, spf_response,
1521 record, strlen(record),
1527 size =
sizeof(SPF_macro_t) + spf_macro->macro_len;
1528 *spf_macrop = (SPF_macro_t *)malloc(size);
int strncasecmp(const char *s1, const char *s2, size_t n)
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,...)
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,...)
SPF_errcode_t SPF_response_add_warn(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
SPF_errcode_t SPF_response_add_error(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
int SPF_response_messages(SPF_response_t *rp)
char SPF_error_errorp(SPF_error_t *err)
SPF_errcode_t SPF_error_code(SPF_error_t *err)
int SPF_response_errors(SPF_response_t *rp)
SPF_record_t * SPF_record_new(SPF_server_t *spf_server, const char *text)
#define SPF_ASSERT_NOTNULL(x)
#define SPF_error(errmsg)
#define SPF_ENSURE_STRING_AVAIL(_len)
#define SPF_RECORD_BUFSIZ
#define STREQ_SIZEOF(a, b)
#define SPF_ADD_LEN_TO(_val, _len, _max)
#define SPF_FINI_STRING_LITERAL()
SPF_errcode_t SPF_record_compile(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_record_t **spf_recordp, const char *record)
#define ALIGNED_DECL(var)
#define STREQ_SIZEOF_N(a, b, n)
#define SPF_INIT_STRING_LITERAL(_avail)
#define SPF_CHECK_IN_MODIFIER()
#define spf_num_mechanisms
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)
unsigned short delim_under
unsigned short delim_dash
unsigned short delim_plus
unsigned short delim_equal
unsigned short url_encode
unsigned char is_dns_mech
SPF_domspec_t has_domainspec