85 if (helo && str_len(helo)) {
92 if (mf && str_len(mf)) {
95 at = str_rchr(
spfmf.s,
'@');
96 if (
spfmf.s[at] ==
'@') {
125 if (!
spf_info(
"P=",
"Maximum nesting level exceeded; possible loop"))
return SPF_NOMEM;
135static struct spf_aliases {
160 stralloc spfdata = {0};
162 struct spf_aliases *da;
163 int first = !recursion;
202 local_pos = spfdata.len;
205 if (!stralloc_0(&spfdata))
return SPF_NOMEM;
210 if (!stralloc_0(&spfdata))
return SPF_NOMEM;
213 if (first && localrules) {
216 while (pos < spfdata.len) {
217 NXTOK(begin,pos,&spfdata);
218 if (!spfdata.s[begin])
continue;
220 if (
p && spfdata.s[begin] != *
p)
p = (
char *) 0;
221 if (!
p && (spfdata.s[begin] ==
'-' ||
222 spfdata.s[begin] ==
'~' ||
223 spfdata.s[begin] ==
'?'))
p = &spfdata.s[begin];
225 if (
p &&
p > spfdata.s && case_equals(spfdata.s + begin + 1,
"all")) {
227 local_pos =
p - spfdata.s;
229 if (!stralloc_readyplus(&spfdata,
spflocalrules.len))
return 0;
230 p = spfdata.s + local_pos;
240 if (pos >= spfdata.len) pos = spfdata.len - 1;
241 for (i = 0; i < pos; i++)
242 if (!spfdata.s[i]) spfdata.s[i] =
' ';
253 while (pos < spfdata.len) {
254 NXTOK(begin,pos,&spfdata);
255 if (!spfdata.s[begin])
continue;
257 if (!
done && localrules) {
258 if (local_pos >= 0 && begin >= local_pos) {
267 for (
p = spfdata.s + begin; *
p; ++
p)
268 if (*
p ==
':' || *
p ==
'/' || *
p ==
'=')
break;
273 if (case_equals(spfdata.s + begin,
"redirect")) {
283 }
else if (case_equals(spfdata.s + begin,
"default")) {
286 for (da = spf_aliases; da->alias; ++da)
287 if (case_equals(da->alias,
p))
break;
290 }
else if (case_equals(spfdata.s + begin,
"exp")) {
293 if (!first)
continue;
296 switch (dns_txt(&
out,&
sa)) {
309 switch (spfdata.s[begin]) {
310 case '-': begin++; spfrc =
SPF_FAIL;
break;
312 case '+': begin++; spfrc =
SPF_OK;
break;
332 if (q ==
SPF_OK) q = spfrc;
342 case SPF_ERROR:
if (localrules)
if (local_pos >= 0 && begin >= local_pos)
break;
361static struct mechanisms {
363 int (*func)(
char *spfspec,
char *prefix);
364 unsigned int use_spfspec : 1;
365 unsigned int use_prefix : 1;
366 unsigned int expands : 1;
367 unsigned int filldomain : 1;
370 {
"all", 0, 0,0,0,0,
SPF_OK }
372, {
"a",
spf_a, 1,1,1,1,0 }
373, {
"mx",
spf_mx, 1,1,1,1,0 }
378, {
"extension",0, 1,1,0,0,
SPF_EXT }
393 struct mechanisms *mech;
398 for (mech = mechanisms; mech->mechanism; mech++)
399 if (case_equals(mech->mechanism,mechanism))
break;
401 if (mech->use_spfspec && !spfspec && mech->filldomain) spfspec =
domain;
402 if (!mech->use_spfspec != !spfspec)
return SPF_SYNTAX;
405 if (!mech->func)
return mech->defresult;
408 if (mech->expands && case_diffs(spfspec,
domain)) {
410 for (pos = 0; (
sa.len - pos) > 255;) {
411 pos += byte_chr(
sa.s + pos,
sa.len - pos,
'.');
412 if (pos <
sa.len) pos++;
415 if (pos > 0) byte_copy(
sa.s,
sa.len,
sa.s + pos);
420 r = mech->func(spfspec,prefix);
467 if (!stralloc_readyplus(
sa,3))
return 0;
470 for (
p = spfspec; *
p; ++
p) {
472 if (byte_equal(
p,1,
"%")) {
476 case '_': append =
' ';
break;
477 case '-':
if (!stralloc_cats(
sa,
"%20"))
return 0;
continue;
479 pos = str_chr(
p,
'}');
480 if (
p[pos] !=
'}') {
p--;
break; }
488 if (!stralloc_append(
sa,&append))
return 0;
504 static const char hextab[] =
"0123456789abcdef";
513 int start = expand->len;
517 if (*macro ==
'x') { urlencode = -1; ++macro; }
else urlencode = 0;
519 if (!ch) {
return 1; }
520 if (ch >=
'A' && ch <=
'Z') { ch += 32; urlencode = 1; }
521 if (urlencode == -1) ch -= 32;
528 if (*macro ==
'}')
break;
529 if (*macro >=
'0' && *macro <=
'9') {
530 scan_ulong(macro,&u); ndigits = u;
531 }
else if (i > 1 && *macro ==
'r') { reverse = 1;
break; }
537 if (!stralloc_readyplus(&
sa,
spfmf.len))
return 0;
543 if (!stralloc_copyb(&
sa,
spfmf.s,i))
return 0;
550 if (i >
spfmf.len)
break;
556 case 'i':
case 'c':
case 'I':
case 'C':
557 if (!stralloc_ready(&
sa,IPFMT))
return 0;
576 if (!stralloc_ready(&
sa,FMT_ULONG))
return 0;
577 sa.len = fmt_ulong(
sa.s,(
unsigned long)
now());
591 if (!stralloc_0(&
sa))
return 0;
595 for (i = 1; i <=
sa.len; i++) {
596 if ((ndigits == -1) || (n < ndigits)) {
597 if (!byte_diff(
sa.s +
sa.len - i - 1,1,
".") || (i ==
sa.len)) {
599 if (!stralloc_cats(expand,
sa.s +
sa.len - i))
return 0;
601 sa.s[
sa.len - i - 1] = 0;
602 if (!stralloc_cats(expand,
"."))
return 0;
607 }
else if (ndigits != -1) {
609 for (i = 1; i <=
sa.len; i++) {
611 if (!byte_diff(
sa.s + i,1,
".")) { n++; pos = i; }
614 if (!stralloc_catb(expand,
sa.s,pos))
return 0;
616 if (!stralloc_cats(expand,
sa.s))
return 0;
619 stralloc_copyb(&
sa,expand->s + start,expand->len - start);
622 for (i = 0; i <
sa.len; ++i) {
624 if (urlchr_table[(
unsigned char)ch]) {
625 if (!stralloc_readyplus(expand,3))
return 0;
626 if (!stralloc_append(expand,
"%"))
return 0;
627 ascii = hextab[(
unsigned char)ch >> 4];
628 if (!stralloc_append(expand,&ascii))
return 0;
629 ascii = hextab[(
unsigned char)ch & 0x0f];
630 if (!stralloc_append(expand,&ascii))
return 0;
632 if (!stralloc_append(expand,&ch))
return 0;
642 if (!stralloc_cats(&
spfinfo,s))
return 0;
643 if (!stralloc_cats(&
spfinfo,t))
return 0;
644 if (!stralloc_cats(&
spfinfo,
" "))
return 0;
int stralloc_copys(stralloc *, char const *)
void p(char *, char *, int, int, int)
int ipme_is6(struct ip6_address *)
int ipme_is4(struct ip4_address *)
int spf_info(char *s, const char *t)
int spf_lookup(stralloc *domain)
spf_lookup calles the actual (recursive) SPF DNS query
int spf_mechanism(char *mechanism, char *spfspec, char *prefix, char *domain)
spf_mechanism evaluates the provided mechanisms in the SPF record [RFC7208 Sec 5.]
int spf_include(char *spfspec, char *prefix)
spf_include deals with recursive evaluation of SPF record [RFC7208 Sec. 5.2]
int spf_macros(stralloc *expand, char *macro, char *domain)
spf_macros deals with macros in the SPF specificaton [RFC7208 Sec. 7ff]
int spf_parse(stralloc *sa, char *spfspec, char *domain)
spf_parse parses the substructure of the SPF record and calls spf_macros
int spf_query(const char *remoteip, const char *helo, const char *mf, const char *local, const int flagip)
spf_query prepares the SPF TXT record query
int spf_ip6(char *, char *)
spf_ip6 (ip6; ip6:fqdn; ip6:fqdn/56) compares AAAA records for SPF info and client host
int spf_a(char *, char *)
spf_a (a; a:fqdns; a:fqdns/56) compares A + AAAA records for SPF info and client host
int get_prefix(char *)
get_prefix return integer value of prefix length
int spf_exists(char *, char *)
spf_exists (exists; exists:fqdn) simply looks for a A records only for SPF info and client host
int spf_mx(char *, char *)
spf_mx (mx; mx:domain; mx:domain/24) compares MX records for SPF info and client host
int spf_ip4(char *, char *)
spf_ip4 (ip4; ip4:fqdn; ip4:fqdn/24) compares A records for SPF info and client host
int spf_ptr(char *, char *)
spf_ptr (ptr; ptr:fqdn) compares PTR records from SPF info and client host
int spf_records(stralloc *, stralloc *)
spf_records get TXT records for domain and extract SPF information