libspf2 1.2.11
spfquery.c
Go to the documentation of this file.
1/*
2 * spfquery - Sender Policy Framwork command line utility
3 *
4 * Author: Wayne Schlitt <wayne@midwestcs.com>
5 *
6 * File: spfquery.c
7 * Desc: SPF command line utility
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of either:
12 *
13 * a) The GNU Lesser General Public License as published by the Free
14 * Software Foundation; either version 2.1, or (at your option) any
15 * later version,
16 *
17 * OR
18 *
19 * b) The two-clause BSD license.
20 *
21 *
22 * The two-clause BSD license:
23 *
24 *
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 *
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
38 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
40 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
44 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46
47#define SPF_TEST_VERSION "3.0"
48
49#ifdef HAVE_CONFIG_H
50# include "config.h"
51#endif
52
53#ifdef STDC_HEADERS
54# include <stdio.h>
55# include <stdlib.h> /* malloc / free */
56#endif
57
58#ifdef HAVE_SYS_TYPES_H
59#include <sys/types.h> /* types (u_char .. etc..) */
60#endif
61
62#ifdef HAVE_INTTYPES_H
63#include <inttypes.h>
64#endif
65
66#ifdef HAVE_STRING_H
67# include <string.h> /* strstr / strdup */
68#else
69# ifdef HAVE_STRINGS_H
70# include <strings.h> /* strstr / strdup */
71# endif
72#endif
73
74#ifdef HAVE_SYS_SOCKET_H
75# include <sys/socket.h> /* inet_ functions / structs */
76#endif
77#ifdef HAVE_NETINET_IN_H
78# include <netinet/in.h> /* inet_ functions / structs */
79#endif
80
81#ifdef HAVE_ARPA_NAMESER_H
82# include <arpa/nameser.h> /* DNS HEADER struct */
83#endif
84
85#ifdef HAVE_ARPA_INET_H
86# include <arpa/inet.h> /* in_addr struct */
87#endif
88
89#define _GNU_SOURCE
90#include <getopt.h>
91
92#ifdef _WIN32
93#include "spf_win32.h"
94#endif
95
96#include "spf.h"
97#include "spf_dns.h"
98#include "spf_dns_null.h"
99#include "spf_dns_test.h"
100#include "spf_dns_cache.h"
101#ifndef _WIN32
102#include "spf_dns_resolv.h"
103#else
104#include "spf_dns_windns.h"
105#endif
106
107
108
109#define TRUE 1
110#define FALSE 0
111
112#define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
113#define FREE_REQUEST(x) FREE((x), SPF_request_free)
114#define FREE_RESPONSE(x) FREE((x), SPF_response_free)
115
116#define CONTINUE_ERROR do { res = 255; continue; } while(0)
117#define WARN_ERROR do { res = 255; } while(0)
118#define FAIL_ERROR do { res = 255; goto error; } while(0)
119
120#define RESIZE_RESULT(n) do { \
121 if (result == NULL) { \
122 result_len = 256 + n; \
123 result = malloc(result_len); \
124 result[0] = '\0'; \
125 } \
126 else if (strlen(result) + n >= result_len) { \
127 result_len = result_len + (result_len >> 1) + 8 + n; \
128 result = realloc(result, result_len); \
129 } \
130} while(0)
131#define APPEND_RESULT(n) do { \
132 partial_result = SPF_strresult(n); \
133 RESIZE_RESULT(strlen(partial_result)); \
134 strcat(result, partial_result); \
135} while(0)
136
137#define X_OR_EMPTY(x) ((x) ? (x) : "")
138
139static struct option long_options[] = {
140 {"file", 1, 0, 'f'},
141
142 {"ip", 1, 0, 'i'},
143 {"sender", 1, 0, 's'},
144 {"helo", 1, 0, 'h'},
145 {"rcpt-to", 1, 0, 'r'},
146
147 {"debug", 2, 0, 'd'},
148 {"local", 1, 0, 'l'},
149 {"trusted", 1, 0, 't'},
150 {"guess", 1, 0, 'g'},
151 {"default-explanation", 1, 0, 'e'},
152 {"max-lookup", 1, 0, 'm'},
153 {"sanitize", 1, 0, 'c'},
154 {"name", 1, 0, 'n'},
155 {"override", 1, 0, 'a'},
156 {"fallback", 1, 0, 'z'},
157
158 {"keep-comments", 0, 0, 'k'},
159 {"version", 0, 0, 'v'},
160 {"help", 0, 0, '?'},
161
162 {0, 0, 0, 0}
163};
164
165static void
166unimplemented(const char flag)
167{
168 struct option *opt;
169 int i;
170
171 for (i = 0; (opt = &long_options[i])->name; i++) {
172 if (flag == opt->val) {
173 fprintf(stderr, "Unimplemented option: -%s or -%c\n",
174 opt->name, flag);
175 return;
176 }
177 }
178
179 fprintf(stderr, "Unimplemented option: -%c\n", flag);
180}
181
182
183static void
184usage()
185{
186 fprintf(
187 stderr,
188 "Usage:\n"
189 "\n"
190 "spfquery [control options | data options] ...\n"
191 "\n"
192 "Use the -help option for more information\n"
193 );
194}
195
196static void
197help()
198{
199 fprintf(
200 stderr,
201 "Usage:\n"
202 "\n"
203 "spfquery [control options | data options] ...\n"
204 "\n"
205 "Valid data options are:\n"
206 " -file <filename> read spf data from a file. Use '-'\n"
207 " to read from stdin.\n"
208 "\n"
209 " -ip <IP address> The IP address that is sending email\n"
210 " -sender <email address> The email address used as the\n"
211 " envelope-from. If no username (local\n"
212 " part) is given, 'postmaster' will be\n"
213 " assumed.\n"
214 " -helo <domain name> The domain name given on the SMTP HELO\n"
215 " command. This is only needed if the\n"
216 " -sender option is not given.\n"
217 " -rcpt-to <email addresses> A comma separated lists of email addresses\n"
218 " that will have email from their secondary\n"
219 " MXes automatically allowed.\n"
220 "\n"
221 "The data options are required. The -file option conflicts with all\n"
222 "the other data options. The -helo and -rcpt-to are optional.\n"
223 "\n"
224 "\n"
225 "Valid control options are:\n"
226 " -debug [debug level] debug level.\n"
227 " -local <SPF mechanisms> Local policy for whitelisting.\n"
228 " -trusted <0|1> Should trusted-forwarder.org be checked?\n"
229 " -guess <SPF mechanisms> Default checks if no SPF record is found.\n"
230 " -default-explanation <str> Default explanation string to use.\n"
231 " -max-lookup <number> Maximum number of DNS lookups to allow\n"
232 " -sanitize <0|1> Clean up invalid characters in output?\n"
233 " -name <domain name> The name of the system doing the SPF\n"
234 " checking\n"
235 " -override <...> Override SPF records for domains\n"
236 " -fallback <...> Fallback SPF records for domains\n"
237 "\n"
238 " -keep-comments Print comments found when reading\n"
239 " from a file.\n"
240 " -version Print version of spfquery.\n"
241 " -help Print out these options.\n"
242 "\n"
243 "Examples:\n"
244 "\n"
245 "spfquery -ip=11.22.33.44 -sender=user@aol.com -helo=spammer.tld\n"
246 "spfquery -f test_data\n"
247 "echo \"127.0.0.1 myname@mydomain.com helohost.com\" | spfquery -f -\n"
248 );
249}
250
251
252static void
253response_print_errors(const char *context,
254 SPF_response_t *spf_response, SPF_errcode_t err)
255{
256 SPF_error_t *spf_error;
257 int i;
258
259 printf("StartError\n");
260
261 if (context != NULL)
262 printf("Context: %s\n", context);
263 if (err != SPF_E_SUCCESS)
264 printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
265
266 if (spf_response != NULL) {
267 for (i = 0; i < SPF_response_messages(spf_response); i++) {
268 spf_error = SPF_response_message(spf_response, i);
269 printf( "%s: %s%s\n",
270 SPF_error_errorp(spf_error) ? "Error" : "Warning",
271 // SPF_error_code(spf_error),
272 // SPF_strerror(SPF_error_code(spf_error)),
273 ((SPF_error_errorp(spf_error) && (!err))
274 ? "[UNRETURNED] "
275 : ""),
276 SPF_error_message(spf_error) );
277 }
278 }
279 else {
280 printf("libspf2 gave a NULL spf_response\n");
281 }
282 printf("EndError\n");
283}
284
285static void
286response_print(const char *context, SPF_response_t *spf_response)
287{
288 printf("--vv--\n");
289 printf("Context: %s\n", context);
290 if (spf_response == NULL) {
291 printf("NULL RESPONSE!\n");
292 }
293 else {
294 printf("Response result: %s\n",
295 SPF_strresult(SPF_response_result(spf_response)));
296 printf("Response reason: %s\n",
297 SPF_strreason(SPF_response_reason(spf_response)));
298 printf("Response err: %s\n",
299 SPF_strerror(SPF_response_errcode(spf_response)));
300 response_print_errors(NULL, spf_response,
301 SPF_response_errcode(spf_response));
302 }
303 printf("--^^--\n");
304}
305
306typedef
307struct SPF_client_options_struct {
308 // void *hook;
310 const char *explanation;
311 const char *fallback;
312 const char *rec_dom;
316 int debug;
318
319typedef
320struct SPF_client_request_struct {
321 char *ip;
322 char *sender;
323 char *helo;
324 char *rcpt_to;
326
327int main( int argc, char *argv[] )
328{
331
332 SPF_server_t *spf_server = NULL;
333 SPF_request_t *spf_request = NULL;
334 SPF_response_t *spf_response = NULL;
335 SPF_response_t *spf_response_2mx = NULL;
336 SPF_response_t *spf_response_fallback = NULL;
337 SPF_errcode_t err;
338
339 char *opt_file = NULL;
340 int opt_keep_comments = 0;
341
342 FILE *fin;
343 char in_line[4096];
344 char *p, *p_end;
345 int done_once;
346 int major, minor, patch;
347
348 int res = 0;
349 int c;
350
351 const char *partial_result;
352 char *result = NULL;
353 int result_len = 0;
354
355 opts = (SPF_client_options_t *)malloc(sizeof(SPF_client_options_t));
356 memset(opts, 0, sizeof(SPF_client_options_t));
357
358 req = (SPF_client_request_t *)malloc(sizeof(SPF_client_request_t));
359 memset(req, 0, sizeof(SPF_client_request_t));
360
361 opts->rec_dom = "spfquery";
362
363#ifdef _WIN32
364 if (SPF_win32_startup() == 0) {
365 fprintf( stderr, "Could not startup WinSock, wrong version." );
367 }
368#endif
369
370 /*
371 * check the arguments
372 */
373
374 for (;;) {
375 int option_index; /* Largely unused */
376
377 c = getopt_long_only (argc, argv, "f:i:s:h:r:lt::gemcnd::kz:a:v",
378 long_options, &option_index);
379
380 if (c == -1)
381 break;
382
383 switch (c) {
384 case 'f':
385 opt_file = optarg;
386 break;
387
388
389 case 'i':
390 req->ip = optarg;
391 break;
392
393 case 's':
394 req->sender = optarg;
395 break;
396
397 case 'h':
398 req->helo = optarg;
399 break;
400
401 case 'r':
402 req->rcpt_to = optarg;
403 break;
404
405
406 case 'l':
407 opts->localpolicy = optarg;
408 break;
409
410 case 't':
411 if (optarg == NULL)
412 opts->use_trusted = 1;
413 else
414 opts->use_trusted = atoi(optarg);
415 break;
416
417 case 'g':
418 opts->fallback = optarg;
419 break;
420
421 case 'e':
422 opts->explanation = optarg;
423 break;
424
425 case 'm':
426 opts->max_lookup = atoi(optarg);
427 break;
428
429 case 'c': /* "clean" */
430 opts->sanitize = atoi(optarg);
431 break;
432
433 case 'n': /* name of host doing SPF checking */
434 opts->rec_dom = optarg;
435 break;
436
437 case 'a':
438 unimplemented('a');
439 break;
440
441 case 'z':
442 unimplemented('z');
443 break;
444
445
446 case 'v':
447 fprintf( stderr, "spfquery version information:\n" );
448 fprintf( stderr, "SPF test system version: %s\n",
450 fprintf( stderr, "Compiled with SPF library version: %d.%d.%d\n",
453 SPF_get_lib_version( &major, &minor, &patch );
454 fprintf( stderr, "Running with SPF library version: %d.%d.%d\n",
455 major, minor, patch );
456 fprintf( stderr, "\n" );
457 usage();
459 break;
460
461 case 0:
462 case '?':
463 help();
465 break;
466
467 case 'k':
468 opt_keep_comments = 1;
469 break;
470
471 case 'd':
472 if (optarg == NULL)
473 opts->debug = 1;
474 else
475 opts->debug = atoi( optarg );
476 break;
477
478 default:
479 fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c);
481 }
482 }
483
484 if (optind != argc) {
485 help();
487 }
488
489 /*
490 * set up the SPF configuration
491 */
492
493 spf_server = SPF_server_new(SPF_DNS_CACHE, opts->debug);
494
495 if ( opts->rec_dom )
496 SPF_server_set_rec_dom( spf_server, opts->rec_dom );
497 if ( opts->sanitize )
498 SPF_server_set_sanitize( spf_server, opts->sanitize );
499 if ( opts->max_lookup )
500 SPF_server_set_max_dns_mech(spf_server, opts->max_lookup);
501
502 if (opts->localpolicy) {
503 err = SPF_server_set_localpolicy( spf_server, opts->localpolicy, opts->use_trusted, &spf_response);
504 if ( err ) {
505 response_print_errors("Error setting local policy",
506 spf_response, err);
508 }
509 FREE_RESPONSE(spf_response);
510 }
511
512
513 if ( opts->explanation ) {
514 err = SPF_server_set_explanation( spf_server, opts->explanation, &spf_response );
515 if ( err ) {
516 response_print_errors("Error setting default explanation",
517 spf_response, err);
519 }
520 FREE_RESPONSE(spf_response);
521 }
522
523 /*
524 * process the SPF request
525 */
526
527 if (opt_file) {
528 /*
529 * the requests are on STDIN
530 */
531 if (strcmp(opt_file, "-" ) == 0)
532 fin = stdin;
533 else
534 fin = fopen( opt_file, "r" );
535
536 if (!fin) {
537 fprintf( stderr, "Could not open: %s\n", opt_file );
539 }
540 }
541 else {
542 fin = NULL;
543
544 if ((req->ip == NULL) ||
545 (req->sender == NULL && req->helo == NULL) ) {
546 usage();
548 }
549 }
550
551 done_once = FALSE;
552
553 while ( TRUE ) {
554 if ( fin ) {
555 if ( fgets( in_line, sizeof( in_line ), fin ) == NULL )
556 break;
557
558 in_line[strcspn(in_line, "\r\n")] = '\0';
559 p = in_line;
560
561 p += strspn( p, " \t\n" );
562 {
563 if ( *p == '\0' || *p == '#' ) {
564 if ( opt_keep_comments )
565 printf( "%s\n", in_line );
566 continue;
567 }
568 }
569 req->ip = p;
570 p += strcspn( p, " \t\n" );
571 *p++ = '\0';
572
573 p += strspn( p, " \t\n" );
574 req->sender = p;
575 p += strcspn( p, " \t\n" );
576 *p++ = '\0';
577
578 p += strspn( p, " \t\n" );
579 req->helo = p;
580 p += strcspn( p, " \t\n" );
581 *p++ = '\0';
582
583 p += strspn( p, " \t\n" );
584 req->rcpt_to = p;
585 p += strcspn( p, " \t\n" );
586 *p++ = '\0';
587 }
588 else {
589 if ( done_once )
590 break;
591 done_once = TRUE;
592 }
593
594 /* We have to do this here else we leak on CONTINUE_ERROR */
595 FREE_REQUEST(spf_request);
596 FREE_RESPONSE(spf_response);
597
598 spf_request = SPF_request_new(spf_server);
599
600 if (SPF_request_set_ipv4_str(spf_request, req->ip)
601 && SPF_request_set_ipv6_str(spf_request, req->ip)) {
602 printf( "Invalid IP address.\n" );
604 }
605
606 if (req->helo) {
607 if (SPF_request_set_helo_dom( spf_request, req->helo ) ) {
608 printf( "Invalid HELO domain.\n" );
610 }
611 }
612
613 if (SPF_request_set_env_from( spf_request, req->sender ) ) {
614 printf( "Invalid envelope from address.\n" );
616 }
617
618 err = SPF_request_query_mailfrom(spf_request, &spf_response);
619 if (opts->debug)
620 response_print("Main query", spf_response);
621 if (err) {
622 response_print_errors("Failed to query MAIL-FROM",
623 spf_response, err);
625 }
626
627 if (result != NULL)
628 result[0] = '\0';
629 APPEND_RESULT(SPF_response_result(spf_response));
630
631 if (req->rcpt_to != NULL && *req->rcpt_to != '\0' ) {
632 p = req->rcpt_to;
633 p_end = p + strcspn(p, ",;");
634
635 /* This is some incarnation of 2mx mode. */
636 while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
637 if (*p_end)
638 *p_end = '\0';
639 else
640 p_end = NULL; /* Note this is last rcpt */
641
642 err = SPF_request_query_rcptto(spf_request,
643 &spf_response_2mx, p);
644 if (opts->debug)
645 response_print("2mx query", spf_response_2mx);
646 if (err) {
647 response_print_errors("Failed to query RCPT-TO",
648 spf_response, err);
650 }
651
652 /* append the result */
653 APPEND_RESULT(SPF_response_result(spf_response_2mx));
654
655 spf_response = SPF_response_combine(spf_response,
656 spf_response_2mx);
657
658 if (!p_end)
659 break;
660 p = p_end + 1;
661 }
662 }
663
664 /* We now have an option to call SPF_request_query_fallback */
665 if (opts->fallback) {
666 err = SPF_request_query_fallback(spf_request,
667 &spf_response_fallback, opts->fallback);
668 if (opts->debug)
669 response_print("fallback query", spf_response_fallback);
670 if (err) {
671 response_print_errors("Failed to query best-guess",
672 spf_response_fallback, err);
674 }
675
676 /* append the result */
677 APPEND_RESULT(SPF_response_result(spf_response_fallback));
678
679 spf_response = SPF_response_combine(spf_response,
680 spf_response_fallback);
681 }
682
683 printf( "%s\n%s\n%s\n%s\n",
684 result,
688 );
689
690 res = SPF_response_result(spf_response);
691
692 fflush(stdout);
693 }
694
695 error:
696 FREE(result, free);
697 FREE_RESPONSE(spf_response);
698 FREE_REQUEST(spf_request);
699 FREE(spf_server, SPF_server_free);
700
701 FREE(req, free);
702 FREE(opts, free);
703
704#ifdef _WIN32
705 SPF_win32_cleanup();
706#endif
707
708 return res;
709}
int main(int argc, char *argv[])
Definition: spfquery.c:327
#define CONTINUE_ERROR
Definition: spfquery.c:116
#define X_OR_EMPTY(x)
Definition: spfquery.c:137
#define FREE_RESPONSE(x)
Definition: spfquery.c:114
#define FAIL_ERROR
Definition: spfquery.c:118
#define APPEND_RESULT(n)
Definition: spfquery.c:131
#define WARN_ERROR
Definition: spfquery.c:117
#define FREE_REQUEST(x)
Definition: spfquery.c:113
#define FREE(x, f)
Definition: spfquery.c:112
#define TRUE
Definition: spfquery.c:109
#define FALSE
Definition: spfquery.c:110
#define SPF_TEST_VERSION
Definition: spfquery.c:47
void usage(void)
Definition: spfd.c:442
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
Definition: spf_server.c:132
@ SPF_DNS_CACHE
Definition: spf_server.h:73
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
Definition: spf_server.c:235
void SPF_server_free(SPF_server_t *sp)
Definition: spf_server.c:200
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
Definition: spf_server.c:228
SPF_errcode_t SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy, int use_default_whitelist, SPF_response_t **spf_responsep)
Definition: spf_server.c:267
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
Definition: spf_server.c:215
@ SPF_RESULT_PASS
Definition: spf_response.h:82
SPF_errcode_t SPF_response_errcode(SPF_response_t *rp)
Definition: spf_response.c:147
const char * SPF_response_get_smtp_comment(SPF_response_t *rp)
Definition: spf_response.c:171
const char * SPF_response_get_received_spf(SPF_response_t *rp)
Definition: spf_response.c:153
const char * SPF_response_get_header_comment(SPF_response_t *rp)
Definition: spf_response.c:165
const char * SPF_error_message(SPF_error_t *err)
Definition: spf_response.c:320
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_response_t * SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
Definition: spf_response.c:90
SPF_errcode_t
Definition: spf_response.h:119
@ SPF_E_SUCCESS
Definition: spf_response.h:120
SPF_result_t SPF_response_result(SPF_response_t *rp)
Definition: spf_response.c:135
SPF_reason_t SPF_response_reason(SPF_response_t *rp)
Definition: spf_response.c:141
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition: spf_request.c:41
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:106
SPF_errcode_t SPF_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
Definition: spf_request.c:300
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
Definition: spf_request.c:139
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
Definition: spf_request.c:117
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:95
SPF_errcode_t SPF_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
Definition: spf_request.c:340
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
Definition: spf_request.c:270
#define SPF_LIB_VERSION_PATCH
#define SPF_LIB_VERSION_MINOR
#define SPF_LIB_VERSION_MAJOR
#define NULL
Definition: spf_internal.h:28
A testing layer for DNS.
const char * SPF_strerror(SPF_errcode_t spf_err)
Definition: spf_strerror.c:33
void SPF_get_lib_version(int *major, int *minor, int *patch)
Definition: spf_utils.c:38
const char * SPF_strresult(SPF_result_t result)
Definition: spf_utils.c:81
const char * SPF_strreason(SPF_reason_t reason)
Definition: spf_utils.c:128
const char * explanation
Definition: spfquery.c:310
const char * rec_dom
Definition: spfquery.c:312
const char * fallback
Definition: spfquery.c:311