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 
139 static 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 
165 static void
166 unimplemented(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 
183 static void
184 usage()
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 
196 static void
197 help()
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 
252 static void
253 response_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 
285 static void
286 response_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 
306 typedef
307 struct SPF_client_options_struct {
308  // void *hook;
309  char *localpolicy;
310  const char *explanation;
311  const char *fallback;
312  const char *rec_dom;
315  int sanitize;
316  int debug;
318 
319 typedef
320 struct SPF_client_request_struct {
321  char *ip;
322  char *sender;
323  char *helo;
324  char *rcpt_to;
326 
327 int main( int argc, char *argv[] )
328 {
329  SPF_client_options_t *opts;
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." );
366  FAIL_ERROR;
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();
458  FAIL_ERROR;
459  break;
460 
461  case 0:
462  case '?':
463  help();
464  FAIL_ERROR;
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);
480  FAIL_ERROR;
481  }
482  }
483 
484  if (optind != argc) {
485  help();
486  FAIL_ERROR;
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);
507  WARN_ERROR;
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);
518  WARN_ERROR;
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 );
538  FAIL_ERROR;
539  }
540  }
541  else {
542  fin = NULL;
543 
544  if ((req->ip == NULL) ||
545  (req->sender == NULL && req->helo == NULL) ) {
546  usage();
547  FAIL_ERROR;
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 SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
#define X_OR_EMPTY(x)
Definition: spfquery.c:137
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
Definition: spf_server.c:228
void SPF_get_lib_version(int *major, int *minor, int *patch)
Definition: spf_utils.c:38
const char * SPF_strerror(SPF_errcode_t spf_err)
Definition: spf_strerror.c:33
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:106
const char * rec_dom
Definition: spfquery.c:312
char SPF_error_errorp(SPF_error_t *err)
Definition: spf_response.c:326
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition: spf_request.c:41
int main(int argc, char *argv[])
Definition: spfquery.c:327
#define CONTINUE_ERROR
Definition: spfquery.c:116
A testing layer for DNS.
#define SPF_LIB_VERSION_PATCH
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
Definition: spf_server.c:215
SPF_errcode_t
Definition: spf_response.h:118
#define NULL
Definition: spf_internal.h:28
SPF_reason_t SPF_response_reason(SPF_response_t *rp)
Definition: spf_response.c:141
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
Definition: spf_request.c:270
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
#define FREE_REQUEST(x)
Definition: spfquery.c:113
#define TRUE
Definition: spfquery.c:109
const char * SPF_response_get_smtp_comment(SPF_response_t *rp)
Definition: spf_response.c:171
void SPF_server_free(SPF_server_t *sp)
Definition: spf_server.c:200
#define FREE(x, f)
Definition: spfquery.c:112
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
Definition: spf_server.c:235
#define APPEND_RESULT(n)
Definition: spfquery.c:131
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
#define FREE_RESPONSE(x)
Definition: spfquery.c:114
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
Definition: spf_request.c:139
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
const char * SPF_error_message(SPF_error_t *err)
Definition: spf_response.c:320
#define SPF_TEST_VERSION
Definition: spfquery.c:47
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
Definition: spf_server.c:132
const char * explanation
Definition: spfquery.c:310
const char * SPF_response_get_header_comment(SPF_response_t *rp)
Definition: spf_response.c:165
const char * SPF_strresult(SPF_result_t result)
Definition: spf_utils.c:81
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:95
#define SPF_LIB_VERSION_MAJOR
#define FALSE
Definition: spfquery.c:110
const char * SPF_response_get_received_spf(SPF_response_t *rp)
Definition: spf_response.c:153
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
Definition: spf_request.c:117
const char * fallback
Definition: spfquery.c:311
const char * SPF_strreason(SPF_reason_t reason)
Definition: spf_utils.c:128
SPF_result_t SPF_response_result(SPF_response_t *rp)
Definition: spf_response.c:135
#define FAIL_ERROR
Definition: spfquery.c:118
SPF_errcode_t SPF_response_errcode(SPF_response_t *rp)
Definition: spf_response.c:147
SPF_response_t * SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
Definition: spf_response.c:90
#define SPF_LIB_VERSION_MINOR
void usage(void)
Definition: spfd.c:442
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
Definition: spf_response.c:308
#define WARN_ERROR
Definition: spfquery.c:117