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 ds_avail = _avail - sizeof(SPF_data_t); \
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)", \
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); \
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 ); \
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,
522 if (spf_server->debug)
523 SPF_debugf(
"Parsing macro starting at %s", src);
526 if ((
void *)data != _align_ptr((
void *)data))
527 SPF_errorf(
"Data pointer %p is not aligned: Cannot compile.",
541 while (idx < src_len) {
542 if (spf_server->debug > 3)
546 len = strcspn(&src[idx],
" %");
549 if (idx + len > src_len)
551 if (spf_server->debug > 3)
552 SPF_debugf(
"Adding string literal (%lu): '%*.*s'",
554 (
int)len, (
int)len, &src[idx]);
557 memcpy(dst, &src[idx], len);
579 if (spf_server->debug > 3)
588 if (spf_server->debug > 3)
597 if (spf_server->debug > 3)
600 *dst++ =
'%'; *dst++ =
'2'; *dst++ =
'0';
606 if (spf_server->debug > 3)
607 SPF_debugf(
"Adding illegal %%-follower '%c' at %d",
619 if (spf_server->debug > 3)
620 SPF_debugf(
"Adding macro, data is at %p", data);
624 err = SPF_c_parse_var(spf_response, &data->
dv, &src[idx], is_mod);
627 idx += strcspn(&src[idx],
"} ");
630 else if (src[idx] ==
' ')
634 "Unterminated variable?");
637 len = SPF_data_len(data);
639 data = SPF_data_next( data );
640 if (spf_server->debug > 3)
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,
682 if (spf_server->debug)
683 SPF_debugf(
"Parsing domainspec starting at %s, cidr is %s",
695 err = SPF_c_parse_cidr(spf_response, &data->
dc, src, &src_len);
699 len = SPF_data_len(data);
701 data = SPF_data_next(data);
704 if (cidr_ok ==
CIDR_ONLY && src_len > 0) {
711 "Invalid CIDR after mechanism");
715 return SPF_c_parse_macro(spf_server, spf_response,
716 data, data_used, data_avail,
717 src, src_len, big_err, is_mod);
727SPF_c_parse_ip4(SPF_response_t *spf_response,
SPF_mech_t *mech,
char const *start)
732 char buf[ INET6_ADDRSTRLEN ];
737 struct in_addr *addr;
740 len = strcspn(start,
" ");
745 while (isdigit( (
unsigned char)(*p) ))
747 if (p != (end - 1) && *p ==
'/') {
748 err = SPF_c_parse_cidr_ip4(spf_response, &mask, p);
756 if ( len >
sizeof( buf ) - 1 )
759 memcpy( buf, start, len );
761 addr = SPF_mech_ip4_data(mech);
762 err = inet_pton( AF_INET, buf, addr );
776SPF_c_parse_ip6(SPF_response_t *spf_response,
SPF_mech_t *mech,
char const *start)
781 char buf[ INET6_ADDRSTRLEN ];
786 struct in6_addr *addr;
789 len = strcspn(start,
" ");
794 while (isdigit( (
unsigned char)(*p) ))
796 if (p != (end - 1) && *p ==
'/') {
797 err = SPF_c_parse_cidr_ip6(spf_response, &mask, p);
805 if ( len >
sizeof( buf ) - 1 )
808 memcpy( buf, start, len );
810 addr = SPF_mech_ip6_data(mech);
811 err = inet_pton( AF_INET6, buf, addr );
824SPF_c_mech_add(SPF_server_t *spf_server,
825 SPF_record_t *spf_record, SPF_response_t *spf_response,
827 const char **mech_value)
842 memset(u.buf,
'B',
sizeof(u.buf));
845 if (spf_server->debug)
846 SPF_debugf(
"SPF_c_mech_add: type=%d, value=%s",
849 spf_mechanism->prefix_type = prefix;
850 spf_mechanism->mech_type = mechtype->
mech_type;
851 spf_mechanism->mech_len = 0;
858 data = SPF_mech_data(spf_mechanism);
861 src_len = strcspn(*mech_value,
" ");
866 if (**mech_value ==
':') {
867 err = SPF_c_parse_ip4(spf_response, spf_mechanism, *mech_value);
868 data_len =
sizeof(
struct in_addr);
874 "Mechanism requires a value.");
879 if (**mech_value ==
':') {
880 err = SPF_c_parse_ip6(spf_response, spf_mechanism, *mech_value);
881 data_len =
sizeof(
struct in6_addr);
887 "Mechanism requires a value.");
892 if (**mech_value ==
':' || **mech_value ==
'=') {
897 "Mechanism does not permit a value.");
900 (*mech_value)++; src_len--;
901 err = SPF_c_parse_domainspec(spf_server,
904 *mech_value, src_len,
909 else if (**mech_value ==
'/') {
914 "Mechanism requires a value.");
920 "Mechanism does not permit a CIDR.");
923 err = SPF_c_parse_domainspec(spf_server,
926 *mech_value, src_len,
931 else if (**mech_value ==
' ' || **mech_value ==
'\0') {
936 "Mechanism requires a value.");
946 "Unknown character '%c' after mechanism.",
951 spf_mechanism->mech_len = data_len;
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)
967 "Failed to allocate memory for mechanism");
968 memcpy( (
char *)spf_record->mech_first + spf_record->mech_len,
971 spf_record->mech_len += len;
972 spf_record->num_mech++;
975 *mech_value += src_len;
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)
1000 if (spf_server->debug)
1001 SPF_debugf(
"Adding modifier name=%lu@%s, value=%s",
1002 (
unsigned long)name_len, mod_name, *mod_value);
1004 memset(u.buf,
'A',
sizeof(u.buf));
1005 memset(spf_modifier, 0,
sizeof(
SPF_mod_t));
1010 spf_modifier->name_len = name_len;
1011 spf_modifier->data_len = 0;
1014 len = _align_sz(
sizeof(
SPF_mod_t ) + name_len);
1019 memcpy(SPF_mod_name(spf_modifier), mod_name, name_len);
1021 data = SPF_mod_data(spf_modifier);
1024 src_len = strcspn(*mod_value,
" ");
1026 err = SPF_c_parse_macro(spf_server,
1029 *mod_value, src_len,
1032 spf_modifier->data_len = data_len;
1037 if (SPF_c_ensure_capacity((
void **)&spf_record->mod_first,
1038 &spf_record->mod_size,
1039 spf_record->mod_len + len) < 0)
1043 "Failed to allocate memory for modifier");
1044 memcpy( (
char *)spf_record->mod_first + spf_record->mod_len,
1047 spf_record->mod_len += len;
1048 spf_record->num_mod++;
1055SPF_record_lint(SPF_server_t *spf_server,
1056 SPF_response_t *spf_response,
1057 SPF_record_t *spf_record)
1065 int found_valid_tld;
1075 mech = spf_record->mech_first;
1077 i < spf_record->num_mech;
1079 mech = SPF_mech_next( mech ) )
1083 && i != spf_record->num_mech - 1 )
1086 "Mechanisms found after the \"all:\" "
1087 "mechanism will be ignored.");
1102 data = SPF_mech_data( mech );
1103 data_end = SPF_mech_end_data( mech );
1104 if ( data == data_end )
1109 data = SPF_data_next( data );
1110 if ( data == data_end )
1115 found_valid_tld =
FALSE;
1116 found_non_ip =
FALSE;
1118 for( d = data; d < data_end; d = SPF_data_next( d ) )
1123 SPF_error(
"Multiple CIDR parameters found" );
1129 found_valid_tld =
FALSE;
1133 found_valid_tld =
FALSE;
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;
1142 found_valid_tld =
TRUE;
1143 else if ( !isalpha( (
unsigned char)( *s ) ) )
1144 found_valid_tld =
FALSE;
1149 found_non_ip =
TRUE;
1150 found_valid_tld =
TRUE;
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");
1181 SPF_response_t *spf_response,
1182 SPF_record_t **spf_recordp,
1186 SPF_record_t *spf_record;
1190 const char *name_start;
1193 const char *val_start;
1194 const char *val_end;
1209 if (spf_server->debug)
1216 *spf_recordp =
NULL;
1226 "Could not find a valid SPF record");
1229 if ( *p !=
'\0' && *p !=
' ' )
1232 "Could not find a valid SPF record");
1235 if (spf_record ==
NULL) {
1236 *spf_recordp =
NULL;
1239 "Failed to allocate an SPF record");
1241 spf_record->version = 1;
1242 *spf_recordp = spf_record;
1247 while (*p !=
'\0') {
1280 while (ispunct((
unsigned char)(*p))) {
1283 "Invalid prefix '%c'", *p);
1290 val_end = name_start + strcspn(p,
" ");
1293 if ( ! isalpha( (
unsigned char)*p ) ) {
1297 "Invalid character at start of mechanism");
1298 p += strcspn(p,
" ");
1301 while ( isalnum( (
unsigned char)*p ) || *p ==
'_' || *p ==
'-' )
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))
1311 name_len = p - name_start;
1313 if (spf_server->debug)
1333 mechtype = SPF_mechtype_find(
MECH_A);
1335 mechtype = SPF_mechtype_find(
MECH_MX);
1337 mechtype = SPF_mechtype_find(
MECH_PTR);
1341 mechtype = SPF_mechtype_find(
MECH_IP4);
1343 mechtype = SPF_mechtype_find(
MECH_IP6);
1347 mechtype = SPF_mechtype_find(
MECH_ALL);
1348#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1350 "default=allow", name_len) )
1354 "Deprecated option 'default=allow'");
1355 mechtype = SPF_mechtype_find(
MECH_ALL);
1359 "default=softfail",name_len))
1363 "Deprecated option 'default=softfail'");
1364 mechtype = SPF_mechtype_find(
MECH_ALL);
1368 "default=deny", name_len) )
1372 "Deprecated option 'default=deny'");
1373 mechtype = SPF_mechtype_find(
MECH_ALL);
1380 "Invalid modifier 'default=...'");
1393 "Unknown mechanism found");
1398 if (mechtype ==
NULL) {
1402 "Failed to find specification for "
1403 "a recognised mechanism");
1406 if (spf_server->debug)
1411 err = SPF_c_mech_add(spf_server,
1412 spf_record, spf_response,
1413 mechtype, prefix, &val_start);
1433 "Modifiers may not have prefixes");
1436#ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1441 name_len = p - name_start;
1452 err = SPF_c_mod_add(spf_server,
1453 spf_record, spf_response,
1454 name_start, name_len, &val_start);
1465 "Invalid character in middle of mechanism");
1475 SPF_record_lint(spf_server, spf_response, spf_record);
1492 "Response has errors but can't find one!");
1500 SPF_response_t *spf_response,
1501 SPF_macro_t **spf_macrop,
1507 SPF_macro_t *spf_macro = (SPF_macro_t *)
ALIGNED_DECL(buf);
1512 data = SPF_macro_data(spf_macro);
1513 spf_macro->macro_len = 0;
1515 err = SPF_c_parse_macro(spf_server, spf_response,
1517 record, strlen(record),
1523 size =
sizeof(SPF_macro_t) + spf_macro->macro_len;
1524 *spf_macrop = (SPF_macro_t *)malloc(size);
int strncasecmp(const char *s1, const char *s2, size_t n)
#define SPF_ASSERT_NOTNULL(x)
#define SPF_error(errmsg)
SPF_record_t * SPF_record_new(SPF_server_t *spf_server, const char *text)
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)
#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