s/qmail 4.2.29a
Next generation secure email transport
Loading...
Searching...
No Matches
spf.c
Go to the documentation of this file.
1#include "stralloc.h"
2#include "alloc.h"
3#include "ip.h"
4#include "ipalloc.h"
5#include "ipme.h"
6#include "str.h"
7#include "fmt.h"
8#include "scan.h"
9#include "byte.h"
10#include "now.h"
11#include "dns.h"
12#include "case.h"
13#include "spf.h"
14
15/* long lived SPF variables (output) */
16
17stralloc spfinfo = {0}; /* SPF results - see spf.h */
18stralloc spfrecord = {0}; /* Used for diagnostics */
19
20/* s/qmail control SPF variables (input) */
21
22stralloc spflocalrules; /* Local rules provided here */
23stralloc spfexplain; /* Default SPF_EXPMSG in spf.h */
24
25stralloc spfmf = {0}; /* aka envelopefrom = clientid */
26stralloc spfhelo = {0}; /* helo or domain part for spfmf */
27stralloc dnsname = {0}; /* FQDN of client host in DNS */
28stralloc spflocal = {0}; /* Receiving host */
29
30stralloc spfexpmsg = {0}; /* additional explanation given as 5xx SMTP response */
31stralloc expdomain = {0}; /* the domain, for which explanation is given */
33
34stralloc domain = {0};
35stralloc identity = {0};
36
37static int recursion;
38char ip4remote[4] = {0, 0, 0, 0};
39char ip6remote[16] = {16 * 0};
40
41/* Sample SPF TXT records:
42Standard example: example.net TXT "v=spf1 mx a:pluto.example.net include:aspmx.googlemail.com -all"
43Fehcom's example: fehcom.net TXT "v=spf1 ip4:85.25.149.179/32 ip6:2001:4dd0:ff00:3d4::2/64 -all"
44Include example: mailing.com TXT "v=spf1 a:smtpout.mailing.com include:spf.nl2go.com ~all"
45Exists+Expand: exists.com TXT "v=spf1 exists:%{ir}.%{l1r+-}._spf.%{d} -all"
46*/
47
48/* Entry point: -------------------------------------- Go for SPF */
49
58int spf_query(const char *remoteip,const char *helo,const char *mf,const char *local,const int flagip)
59{
60 int at;
61 int r = SPF_INIT;
62 flagip6 = flagip;
63
64 if (!stralloc_copys(&spfinfo," ")) return SPF_NOMEM;
65
66 switch (flagip6) {
67 case -1: if (!spf_info("MLocal=",remoteip)) return SPF_NOMEM;
68 if (!spf_info("R:","+")) return SPF_NOMEM;
69 break;
70 case 0: if (!ip4_scan(remoteip,ip4remote)) return SPF_SYNTAX;
71 if (ipme_is4(ip4remote) == 1) {
72 if (!spf_info("MLocal=",remoteip)) return SPF_NOMEM;
73 if (!spf_info("R:","+")) return SPF_NOMEM;
74 return SPF_ME;
75 } break;
76 case 1: if (!ip6_scan(remoteip,ip6remote)) return SPF_SYNTAX;
77 if (ipme_is6(ip6remote) == 1) {
78 if (!spf_info("MLocal=",remoteip)) return SPF_NOMEM;
79 if (!spf_info("R:","+")) return SPF_NOMEM;
80 return SPF_ME;
81 } break;
82 }
83
84 if (helo && str_len(helo)) {
85 if (!stralloc_copys(&spfhelo,helo)) return SPF_NOMEM;
86 } else {
87 if (!stralloc_copys(&spfhelo,"unknown")) return SPF_NOMEM;
88 }
89 if (!stralloc_0(&spfhelo)) return SPF_NOMEM;
90
91 if (mf && str_len(mf)) {
92 if (!stralloc_copys(&spfmf,mf)) return SPF_NOMEM;
93 if (!stralloc_0(&spfmf)) return SPF_NOMEM;
94 at = str_rchr(spfmf.s,'@');
95 if (spfmf.s[at] == '@') {
96 if (!stralloc_copys(&domain,spfmf.s + at + 1)) return SPF_NOMEM;
97 } else {
98// if (!stralloc_0(&spfhelo)) return SPF_NOMEM;
99 if (!stralloc_copys(&domain,&spfhelo)) return SPF_NOMEM;
100 }
101 if (!stralloc_copy(&identity,&domain)) return SPF_NOMEM;
102 }
103 if (!stralloc_0(&identity)) return SPF_NOMEM;
104
105 if (local && str_len(local)) {
106 if (!stralloc_copys(&spflocal,local)) return SPF_NOMEM;
107 } else {
108 if (!stralloc_copys(&spflocal,"localhost")) return SPF_NOMEM;
109 }
110 if (!stralloc_0(&spflocal)) return SPF_NOMEM;
111
112 if (!spf_info("S=",remoteip)) return SPF_NOMEM;
113 if (!spf_info("O=",spfmf.s)) return SPF_NOMEM;
114 if (!spf_info("C=",identity.s)) return SPF_NOMEM;
115 if (!spf_info("H=",spfhelo.s)) return SPF_NOMEM;
116
117 if (!stralloc_copy(&spfexpmsg,&spfexplain)) return SPF_NOMEM;
118 if (!stralloc_0(&spfexpmsg)) return SPF_NOMEM;
119
120 recursion = 0;
121 dnsname.len = 0;
122
123 if (r == SPF_INIT) r = spf_lookup(&domain);
124 if (r == SPF_LOOP) {
125 if (!spf_info("P=","Maximum nesting level exceeded; possible loop")) return SPF_NOMEM;
126 if (!spf_info("R:","e")) return SPF_NOMEM;
127 }
128 if (r < 0) r = SPF_UNKNOWN; /* return 2main */
129
130 return r;
131}
132
133/* SPF Lookup: -------------------------------------- Return cases */
134
135static struct spf_aliases {
136 char *alias;
137 int defrc;
138} spf_aliases[] = {
139 { "allow", SPF_OK }
140, { "pass", SPF_OK }
141, { "deny", SPF_FAIL }
142, { "softdeny",SPF_SOFTFAIL }
143, { "fail", SPF_FAIL }
144, { "softfail",SPF_SOFTFAIL }
145, { "unknown", SPF_NEUTRAL }
146, { 0, SPF_UNKNOWN }
147};
148
158int spf_lookup(stralloc *domain)
159{
160 stralloc spfdata = {0};
161 stralloc sa = {0};
162 struct spf_aliases *da;
163 int first = !recursion;
164 int local_pos = -1;
165 int localrules = 0;
166 int q = -1;
167 int i, r;
168 int begin, pos;
169 int spfrc;
170 int done;
171 char *p;
172
173 /* Fallthrough result */
174
175 REDIRECT:
176 if (++recursion > LOOKUP_LIMIT) return SPF_EXHAUST;
177
178 if (!stralloc_copys(&expdomain,domain->s)) return SPF_NOMEM; // *FIXME */
179
180 if (!stralloc_copys(&spfdata,"")) return SPF_NOMEM;
181 r = spf_records(&spfdata,domain);
182
183 if (!stralloc_0(domain)) return SPF_NOMEM;
184 if (first) if (!stralloc_copys(&spfrecord,"")) return SPF_NOMEM;
185 if (!stralloc_cats(&spfrecord,"(")) return SPF_NOMEM;
186 if (!stralloc_cat(&spfrecord,domain)) return SPF_NOMEM;
187 if (!stralloc_cats(&spfrecord,")")) return SPF_NOMEM;
188 if (!stralloc_cats(&spfrecord," => ")) return SPF_NOMEM;
189 if (!stralloc_cat(&spfrecord,&spfdata)) return SPF_NOMEM;
190 if (!stralloc_cats(&spfrecord,"\n")) return SPF_NOMEM;
191 if (!stralloc_0(&spfrecord)) return SPF_NOMEM;
192
193 /* In spite of none-existing SPF data, use local rules as substitude */
194
195 if (r == SPF_NONE) { /* No SPF records published */
196 if (!first) {
197 return r;
198 } else {
199 spfdata.len = 0;
200 }
201 if (localrules) { /* append local ruleset */
202 local_pos = spfdata.len;
203 if (!stralloc_cats(&spfdata,spflocalrules.s)) return SPF_NOMEM;
204 }
205 if (!stralloc_0(&spfdata)) return SPF_NOMEM;
206
207 if (!stralloc_copys(&expdomain,"")) return SPF_NOMEM;
208
209 } else if (r == SPF_OK) { /* SPF records published */
210 if (!stralloc_0(&spfdata)) return SPF_NOMEM;
211 r = SPF_NEUTRAL;
212
213 if (first && localrules) { /* try to add local rules before failure of all mechs */
214 pos = 0;
215 p = (char *) 0;
216 while (pos < spfdata.len) {
217 NXTOK(begin,pos,&spfdata);
218 if (!spfdata.s[begin]) continue;
219
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];
224
225 if (p && p > spfdata.s && case_equals(spfdata.s + begin + 1,"all")) {
226 /* ok, we can insert the local rules at p */
227 local_pos = p - spfdata.s;
228
229 if (!stralloc_readyplus(&spfdata,spflocalrules.len)) return 0;
230 p = spfdata.s + local_pos;
231 byte_copyr(p + spflocalrules.len,spfdata.len - local_pos,p);
232 byte_copy(p,spflocalrules.len,spflocalrules.s);
233 spfdata.len += spflocalrules.len;
234
235 pos += spflocalrules.len;
236 break;
237 }
238 }
239
240 if (pos >= spfdata.len) pos = spfdata.len - 1;
241 for (i = 0; i < pos; i++)
242 if (!spfdata.s[i]) spfdata.s[i] = ' ';
243 }
244
245 } else { /* Any other SPF return code */
246 return r;
247 }
248
249 /* (artificial) SPF data exist; work thru them */
250
251 pos = 0;
252 done = 0;
253 while (pos < spfdata.len) {
254 NXTOK(begin,pos,&spfdata);
255 if (!spfdata.s[begin]) continue;
256
257 if (!done && localrules) { /* in local ruleset? */
258 if (local_pos >= 0 && begin >= local_pos) {
259 if (begin < (local_pos + spflocalrules.len)) {
260 if (!stralloc_copys(&expdomain,"")) return SPF_NOMEM;
261 } else {
262 if (!stralloc_copy(&expdomain,domain)) return SPF_NOMEM;
263 }
264 }
265 }
266
267 for (p = spfdata.s + begin; *p; ++p)
268 if (*p == ':' || *p == '/' || *p == '=') break;
269
270 if (*p == '=') {
271 *p++ = 0;
272
273 if (case_equals(spfdata.s + begin,"redirect")) { /* modifiers are simply handled here */
274 if (done) continue;
275
276// if (!stralloc_0(domain)) return SPF_NOMEM;
277 if (!spf_parse(&sa,p,domain->s)) return SPF_NOMEM;
278 if (!stralloc_copy(domain,&sa)) return SPF_NOMEM;
279 if (!spf_info("D=",p)) return SPF_NOMEM;
280 r = SPF_UNKNOWN;
281
282 goto REDIRECT;
283 } else if (case_equals(spfdata.s + begin,"default")) { /* we don't need those anymore */
284 if (done) continue;
285
286 for (da = spf_aliases; da->alias; ++da)
287 if (case_equals(da->alias,p)) break;
288
289 r = da->defrc;
290 } else if (case_equals(spfdata.s + begin,"exp")) { /* exp= only on top level */
291 stralloc out = {0};
292
293 if (!first) continue;
294 if (!stralloc_copys(&sa,p)) return SPF_NOMEM;
295
296 switch (dns_txt(&out,&sa)) {
297 case -1: return SPF_NOMEM;
298 case 0: continue; /* nobody @home */
299 }
300
301 if (!stralloc_copys(&spfexpmsg,out.s)) return SPF_NOMEM;
302 if (!stralloc_append(&spfexpmsg,"\n")) return SPF_NOMEM;
303 if (!stralloc_0(&spfexpmsg)) return SPF_NOMEM;
304 }
305 } else if (!done) { /* and unknown modifiers are ignored */
306 if (!stralloc_copys(&sa,spfdata.s + begin)) return SPF_NOMEM;
307 if (!stralloc_0(&sa)) return SPF_NOMEM;
308
309 switch (spfdata.s[begin]) {
310 case '-': begin++; spfrc = SPF_FAIL; break;
311 case '~': begin++; spfrc = SPF_SOFTFAIL; break;
312 case '+': begin++; spfrc = SPF_OK; break;
313 case '?': begin++; spfrc = SPF_NEUTRAL; break;
314 default: spfrc = SPF_OK;
315 }
316
317 if (*p == '/') {
318 *p++ = 0;
319 q = spf_mechanism(spfdata.s + begin,0,p,domain->s);
320 } else {
321 if (*p) *p++ = 0;
322 i = str_chr(p,'/');
323 if (p[i] == '/') {
324 p[i++] = 0;
325 q = spf_mechanism(spfdata.s + begin,p,p + i,domain->s);
326 } else if (i > 0) {
327 q = spf_mechanism(spfdata.s + begin,p,0,domain->s);
328 } else {
329 q = spf_mechanism(spfdata.s + begin,0,0,domain->s);
330 }
331 }
332 if (q == SPF_OK) q = spfrc;
333
334 switch (q) {
335 case SPF_OK: if (!spf_info("R:","+")) return SPF_NOMEM; break;
336 case SPF_NEUTRAL: if (!spf_info("R:","?")) return SPF_NOMEM; break;
337 case SPF_SYNTAX: if (!spf_info("P=","Unknown parse error")) return SPF_NOMEM;
338 if (!spf_info("R:","e")) return SPF_NOMEM; break;
339 case SPF_SOFTFAIL: if (!spf_info("R:","~")) return SPF_NOMEM; break;
340 case SPF_FAIL: if (!spf_info("R:","-")) return SPF_NOMEM; break;
341 case SPF_EXT: if (!spf_info("P=","Unknown SPF mechanism")) return SPF_NOMEM; break;
342 case SPF_ERROR: if (localrules) if (local_pos >= 0 && begin >= local_pos) break;
343 if (!spf_info("R:","o")) return SPF_NOMEM; q = SPF_NONE; break;
344 case SPF_NONE: continue;
345 }
346
347 r = q;
348 done = 1; /* we're done, no more mechanisms */
349 }
350 }
351
352 /* we fell through, no local rule applied */
353 if (!done)
354 if (!stralloc_copy(&expdomain,domain)) return SPF_NOMEM;
355
356 return r;
357}
358
359/* Mechanisms: -------------------------------------- Lookup classes */
360
361static struct mechanisms {
362 char *mechanism;
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;
368 int defresult : 4;
369} mechanisms[] = {
370 { "all", 0, 0,0,0,0,SPF_OK }
371, { "include", spf_include,1,0,1,0,0 }
372, { "a", spf_a, 1,1,1,1,0 }
373, { "mx", spf_mx, 1,1,1,1,0 }
374, { "ptr", spf_ptr, 1,0,1,1,0 }
375, { "ip4", spf_ip4, 1,1,0,0,0 }
376, { "ip6", spf_ip6, 1,1,0,0,0 }
377, { "exists", spf_exists, 1,0,1,0,0 }
378, { "extension",0, 1,1,0,0,SPF_EXT }
379, { 0, 0, 1,1,0,0,SPF_EXT }
380};
381
391int spf_mechanism(char *mechanism,char *spfspec,char *prefix,char *domain)
392{
393 struct mechanisms *mech;
394 stralloc sa = {0};
395 int r;
396 int pos;
397
398 for (mech = mechanisms; mech->mechanism; mech++)
399 if (case_equals(mech->mechanism,mechanism)) break;
400
401 if (mech->use_spfspec && !spfspec && mech->filldomain) spfspec = domain;
402 if (!mech->use_spfspec != !spfspec) return SPF_SYNTAX;
403 if (mech->use_prefix && !get_prefix(prefix)) return SPF_SYNTAX;
404
405 if (!mech->func) return mech->defresult;
406 if (!stralloc_readyplus(&sa,1)) return SPF_NOMEM;
407
408 if (mech->expands && case_diffs(spfspec,domain)) {
409 if (!spf_parse(&sa,spfspec,domain)) return SPF_NOMEM;
410 for (pos = 0; (sa.len - pos) > 255;) {
411 pos += byte_chr(sa.s + pos,sa.len - pos,'.');
412 if (pos < sa.len) pos++;
413 }
414 sa.len -= pos;
415 if (pos > 0) byte_copy(sa.s,sa.len,sa.s + pos);
416 if (!stralloc_0(&sa)) return SPF_NOMEM;
417 spfspec = sa.s;
418 }
419
420 r = mech->func(spfspec,prefix);
421 return r;
422}
423
431int spf_include(char *spfspec,char *prefix)
432{
433 stralloc sa = {0};
434 int r;
435
436 if (!stralloc_copys(&sa,spfspec)) return SPF_NOMEM;
437
438 r = spf_lookup(&sa);
439 switch (r) {
440 case SPF_NONE: r = SPF_UNKNOWN; break;
441 case SPF_SYNTAX: r = SPF_UNKNOWN; break;
442 case SPF_NEUTRAL:
443 case SPF_SOFTFAIL:
444 case SPF_FAIL: r = SPF_NONE; break;
445 }
446 if (!stralloc_0(&sa)) return SPF_NOMEM;
447 if (!spf_info("I=",sa.s)) return SPF_NOMEM;
448
449 return r;
450}
451
461int spf_parse(stralloc *sa,char *spfspec,char *domain)
462{
463 char *p;
464 int pos;
465 char append;
466
467 if (!stralloc_readyplus(sa,3)) return 0;
468 if (!stralloc_copys(sa,"")) return 0;
469
470 for (p = spfspec; *p; ++p) {
471 append = *p;
472 if (byte_equal(p,1,"%")) {
473 p++;
474 switch (*p) {
475 case '%': break;
476 case '_': append = ' '; break;
477 case '-': if (!stralloc_cats(sa,"%20")) return 0; continue;
478 case '{':
479 pos = str_chr(p,'}');
480 if (p[pos] != '}') { p--; break; }
481 p[pos] = '\0';
482 if (!spf_macros(sa,p + 1,domain)) return 0;
483 p += pos;
484 continue;
485 default: p--;
486 }
487 }
488 if (!stralloc_append(sa,&append)) return 0;
489 }
490
491 return 1;
492}
493
502int spf_macros(stralloc *expand,char *macro,char *domain)
503{
504 static const char hextab[] = "0123456789abcdef";
505 stralloc sa = {0};
506 int reverse = 0;
507 int ndigits = -1;
508 int urlencode;
509 unsigned long u;
510 char ch = {0};
511 char ascii;
512 int pos, i, n;
513 int start = expand->len;
514
515 /* URL encoding - hidden in RFC 7208 Sec. 7.3 */
516
517 if (*macro == 'x') { urlencode = -1; ++macro; } else urlencode = 0;
518 ch = *macro;
519 if (!ch) { return 1; }
520 if (ch >= 'A' && ch <= 'Z') { ch += 32; urlencode = 1; }
521 if (urlencode == -1) ch -= 32;
522
523 /* No. digits determine number of printed labels */
524
525 i = 0;
526 while (*macro) {
527 i++;
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; } /* Reverse representation */
532 macro++;
533 }
534
535 switch (ch) { /* see RFC7208 sec. 7.2 */
536 case 's': case 'S':
537 if (!stralloc_readyplus(&sa,spfmf.len)) return 0;
538 if (!stralloc_copys(&sa,spfmf.s)) return 0;
539 break;
540 case 'l': case 'L':
541 i = byte_rchr(spfmf.s,spfmf.len,'@');
542 if (i < spfmf.len) {
543 if (!stralloc_copyb(&sa,spfmf.s,i)) return 0;
544 } else {
545 if (!stralloc_copys(&sa,"postmaster")) return 0;
546 }
547 break;
548 case 'o': case 'O':
549 i = byte_rchr(spfmf.s,spfmf.len,'@') + 1;
550 if (i > spfmf.len) break;
551 if (!stralloc_copys(&sa,spfmf.s + i)) return 0;
552 break;
553 case 'd': case 'D':
554 if (!stralloc_copys(&sa,domain)) return 0; /* the hack for 'Z'; Russions everywhere ;-) */
555 break;
556 case 'i': case 'c': case 'I': case 'C':
557 if (!stralloc_ready(&sa,IPFMT)) return 0;
558 if (flagip6) {
559 sa.len = ip6_fmt(sa.s,ip6remote);
560 } else {
561 sa.len = ip4_fmt(sa.s,ip4remote);
562 }
563 break;
564 case 'p': case 'P':
565 if (!dnsname.len) spf_ptr(domain,0);
566 if (dnsname.len) {
567 if (!stralloc_copys(&sa,dnsname.s)) return 0;
568 } else {
569 if (!stralloc_copys(&sa,"unknown")) return 0;
570 }
571 break;
572 case 'h': case 'H':
573 if (!stralloc_copys(&sa,spfhelo.s)) return 0; /* FIXME: FQDN? */
574 break;
575 case 't': case 'T':
576 if (!stralloc_ready(&sa,FMT_ULONG)) return 0;
577 sa.len = fmt_ulong(sa.s,(unsigned long)now());
578 break;
579 case 'v': case 'V':
580 if (flagip6) {
581 if (!stralloc_copys(&sa,"ip6")) return 0;
582 } else {
583 if (!stralloc_copys(&sa,"in-addr")) return 0;
584 }
585 break;
586 case 'r': case 'R':
587 if (!stralloc_copy(&sa,&spflocal)) return 0;
588 break;
589 default: break;
590 }
591 if (!stralloc_0(&sa)) return 0; // XXX
592
593 if (reverse) {
594 n = 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)) {
598 n++;
599 if (!stralloc_cats(expand,sa.s + sa.len - i)) return 0;
600 if (i < sa.len) {
601 sa.s[sa.len - i - 1] = 0;
602 if (!stralloc_cats(expand,".")) return 0;
603 }
604 }
605 }
606 }
607 } else if (ndigits != -1) {
608 n = pos = 0;
609 for (i = 1; i <= sa.len; i++) {
610 if (n < ndigits) {
611 if (!byte_diff(sa.s + i,1,".")) { n++; pos = i; }
612 }
613 }
614 if (!stralloc_catb(expand,sa.s,pos)) return 0;
615 } else
616 if (!stralloc_cats(expand,sa.s)) return 0;
617
618 if (urlencode) {
619 stralloc_copyb(&sa,expand->s + start,expand->len - start);
620 expand->len = start;
621
622 for (i = 0; i < sa.len; ++i) {
623 ch = sa.s[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;
631 } else {
632 if (!stralloc_append(expand,&ch)) return 0;
633 }
634 }
635 }
636
637 return 1;
638}
639
640int spf_info(char *s,const char *t)
641{
642 if (!stralloc_cats(&spfinfo,s)) return 0;
643 if (!stralloc_cats(&spfinfo,t)) return 0;
644 if (!stralloc_cats(&spfinfo," ")) return 0;
645
646 return 1;
647}
int stralloc_copys(stralloc *, char const *)
stralloc out
Definition: dnscname.c:12
stralloc sa
Definition: dnscname.c:11
strset done
Definition: fastforward.c:75
void p(char *, char *, int, int, int)
Definition: install.c:39
int ipme_is6()
int ipme_is4()
datetime_sec now()
Definition: now.c:5
char * local
Definition: qmail-getpw.c:18
int
Definition: qmail-mrtg.c:26
char * remoteip
Definition: qmail-popup.c:71
stralloc spfhelo
Definition: spf.c:26
stralloc spfexpmsg
Definition: spf.c:30
stralloc expdomain
Definition: spf.c:31
char ip4remote[4]
Definition: spf.c:38
stralloc spflocal
Definition: spf.c:28
int spf_info(char *s, const char *t)
Definition: spf.c:640
int spf_lookup(stralloc *domain)
spf_lookup calles the actual (recursive) SPF DNS query
Definition: spf.c:158
stralloc spfexplain
Definition: spf.c:23
int spf_mechanism(char *mechanism, char *spfspec, char *prefix, char *domain)
spf_mechanism evaluates the provided mechanisms in the SPF record [RFC7208 Sec 5.]
Definition: spf.c:391
stralloc spfinfo
Definition: spf.c:17
stralloc identity
Definition: spf.c:35
int spf_include(char *spfspec, char *prefix)
spf_include deals with recursive evaluation of SPF record [RFC7208 Sec. 5.2]
Definition: spf.c:431
stralloc spfmf
Definition: spf.c:25
int spf_macros(stralloc *expand, char *macro, char *domain)
spf_macros deals with macros in the SPF specificaton [RFC7208 Sec. 7ff]
Definition: spf.c:502
int spf_parse(stralloc *sa, char *spfspec, char *domain)
spf_parse parses the substructure of the SPF record and calls spf_macros
Definition: spf.c:461
stralloc spflocalrules
Definition: spf.c:22
char ip6remote[16]
Definition: spf.c:39
stralloc domain
Definition: spf.c:34
stralloc spfrecord
Definition: spf.c:18
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
Definition: spf.c:58
int flagip6
Definition: spf.c:32
stralloc dnsname
Definition: spf.c:27
#define SPF_LOOP
Definition: spf.h:13
#define SPF_EXT
Definition: spf.h:10
int spf_ip6(char *, char *)
spf_ip6 (ip6; ip6:fqdn; ip6:fqdn/56) compares AAAA records for SPF info and client host
Definition: spfdnsip.c:368
#define SPF_ME
Definition: spf.h:11
int spf_a(char *, char *)
spf_a (a; a:fqdns; a:fqdns/56) compares A + AAAA records for SPF info and client host
Definition: spfdnsip.c:145
#define SPF_ERROR
Definition: spf.h:16
#define SPF_NEUTRAL
Definition: spf.h:25
#define SPF_OK
Definition: spf.h:22
#define SPF_FAIL
Definition: spf.h:27
#define SPF_SOFTFAIL
Definition: spf.h:26
int get_prefix(char *)
get_prefix return integer value of prefix length
Definition: spfdnsip.c:65
int spf_exists(char *, char *)
spf_exists (exists; exists:fqdn) simply looks for a A records only for SPF info and client host
Definition: spfdnsip.c:391
int spf_mx(char *, char *)
spf_mx (mx; mx:domain; mx:domain/24) compares MX records for SPF info and client host
Definition: spfdnsip.c:192
#define SPF_EXHAUST
Definition: spf.h:12
#define SPF_NOMEM
Definition: spf.h:17
int spf_ip4(char *, char *)
spf_ip4 (ip4; ip4:fqdn; ip4:fqdn/24) compares A records for SPF info and client host
Definition: spfdnsip.c:345
#define SPF_SYNTAX
Definition: spf.h:18
int spf_ptr(char *, char *)
spf_ptr (ptr; ptr:fqdn) compares PTR records from SPF info and client host
Definition: spfdnsip.c:235
#define LOOKUP_LIMIT
Definition: spf.h:30
#define SPF_UNKNOWN
Definition: spf.h:24
int spf_records(stralloc *, stralloc *)
spf_records get TXT records for domain and extract SPF information
Definition: spfdnsip.c:93
#define NXTOK(b, p, a)
Definition: spf.h:82
#define SPF_NONE
Definition: spf.h:23
#define SPF_INIT
Definition: spf.h:9