spf_example.c

Go to the documentation of this file.
00001 /*
00002  *  spf_example - An example program for how to use libspf2
00003  *      
00004  *  Author: Wayne Schlitt <wayne@midwestcs.com>
00005  *
00006  *  File:   spfquery.c
00007  *  Desc:   SPF command line utility
00008  *
00009  *
00010  * This program is in the public domain, there is no copyright, you
00011  * can do anything you want with it.
00012  */
00013 
00014 
00015 /*
00016  * The libspf2 library uses the GNU autoconf system to help make
00017  * the library more portable.  The config.h file should have the
00018  * HAVE_xxx defines that are appropriate for your system.  Either use
00019  * autconf to create it, or create it by hand.
00020  */
00021 
00022 
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026 
00027 #ifdef STDC_HEADERS
00028 # include <stdio.h>
00029 # include <stdlib.h>       /* malloc / free */
00030 #endif
00031 
00032 #ifdef HAVE_SYS_TYPES_H
00033 #include <sys/types.h>  /* types (u_char .. etc..) */
00034 #endif
00035 
00036 #ifdef HAVE_INTTYPES_H
00037 #include <inttypes.h>
00038 #endif
00039 
00040 #ifdef HAVE_STRING_H
00041 # include <string.h>       /* strstr / strdup */
00042 #else
00043 # ifdef HAVE_STRINGS_H
00044 #  include <strings.h>     /* strstr / strdup */
00045 # endif
00046 #endif
00047 
00048 #ifdef HAVE_SYS_SOCKET_H
00049 # include <sys/socket.h>   /* inet_ functions / structs */
00050 #endif
00051 #ifdef HAVE_NETINET_IN_H
00052 # include <netinet/in.h>   /* inet_ functions / structs */
00053 #endif
00054 #ifdef HAVE_ARPA_INET_H
00055 # include <arpa/inet.h> /* in_addr struct */
00056 #endif
00057 
00058 #ifdef HAVE_ARPA_NAMESER_H
00059 # include <arpa/nameser.h> /* DNS HEADER struct */
00060 #endif
00061 
00062 #ifdef HAVE_UNISTD_H
00063 #include <unistd.h>
00064 #endif
00065 
00066 #ifdef HAVE_GETOPT_H
00067 #include <getopt.h>
00068 #endif
00069 
00070 
00071 
00072 /*
00073  * libspf2 public include files that are needed for this example
00074  * program
00075  */
00076 
00077 #include "spf.h"
00078 
00079 
00080 /*
00081  * usage() just prints out the command line options for this program
00082  */
00083 static void usage()
00084 {
00085         fprintf(
00086         stderr,
00087         "Usage:\n"
00088         "\n"
00089         "spf_example [options]\n"
00090         "\n"
00091         "Valid data options are:\n"
00092         "    -i <IP address>            The IP address that is sending email\n"
00093         "    -s <email address>         The email address used as the\n"
00094         "                               envelope-from.  If no username (local\n"
00095         "                               part) is given, 'postmaster' will be\n"
00096         "                               assumed.\n"
00097         "    -r <email address>         [optional] The email address used as\n"
00098         "                               the envelope-to email address, for\n"
00099         "                               secondary-MX checking.\n"
00100         "    -h <domain name>           The domain name given on the SMTP HELO\n"
00101         "                               command.  This is only needed if the\n"
00102         "                               -sender option is not given.\n"
00103         "    -d [debug level]           debug level.\n"
00104         );
00105 }
00106 
00107 
00108 
00109 /*
00110  * All the code is in the main routine, but most usages of libspf2
00111  * would have the code spread around into various subrotines.
00112  */
00113 
00114 int main( int argc, char *argv[] )
00115 {
00116         int c;
00117         int     res = 0;
00118         int     i;
00119 
00120         char *opt_ip = NULL;
00121         char *opt_sender = NULL;
00122         char *opt_helo = NULL;
00123         char *opt_rcpt_to = NULL;
00124         int   opt_debug = 0;
00125 
00126         /* You should not indirect on any of these structures, as their
00127          * layout may change between versions of the library. Use the
00128          * accessor functions instead. Definitions of the structs may not
00129          * even be provided. */
00130 
00131         SPF_server_t            *spf_server = NULL;
00132         SPF_request_t           *spf_request = NULL;
00133         SPF_response_t          *spf_response = NULL;
00134         SPF_response_t          *spf_response_2mx = NULL;
00135         
00136 
00137         /*
00138          * check the arguments
00139          */
00140 
00141         while (1)
00142         {
00143         c = getopt(argc, argv, "i:s:h:r:d::" );
00144 
00145         if (c == -1)
00146                 break;
00147 
00148         switch (c)
00149         {
00150         case 'i':
00151                 opt_ip = optarg;
00152                 break;
00153 
00154         case 's':
00155                 opt_sender = optarg;
00156                 break;
00157 
00158         case 'h':
00159                 opt_helo = optarg;
00160                 break;
00161 
00162         case 'r':
00163                 opt_rcpt_to = optarg;
00164                 break;
00165 
00166         case 0:
00167         case '?':
00168                 usage();
00169                 res = 255;
00170                 goto error;
00171                 break;
00172 
00173         case 'd':
00174                 if (optarg == NULL)
00175                 opt_debug = 1;
00176                 else
00177                 opt_debug = atoi( optarg );
00178                 break;
00179 
00180         default:
00181                 fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c);
00182         }
00183         }
00184 
00185         if (optind != argc
00186         || opt_ip == NULL
00187         || (opt_helo == NULL && opt_sender == NULL))
00188         {
00189         usage();
00190         res = 255;
00191         goto error;
00192         }
00193 
00194 /*
00195  * Configure the SPF system.
00196  *
00197  * libspf2 is designed so that configurations can be set up once
00198  * and reused many times different emails delivered in a single SMTP
00199  * session or in different SMTP sessions.
00200  */
00201 
00202         /*
00203          * set up the SPF server
00204          *
00205          * Configurations contain malloc'd data so must be
00206          * destroyed when you are finished.
00207          */
00208 
00209         spf_server = SPF_server_new(SPF_DNS_CACHE, 1);
00210 
00211         if (spf_server == NULL) {
00212                 fprintf( stderr, "SPF_create_config failed.\n" );
00213                 res = 255;
00214                 goto error;
00215         }
00216 
00217         /*
00218          * Create a new request.
00219          *
00220          * The SPF request contains all the data needed to process
00221          * the SPF check. Requests are malloc'd so it must be
00222          * destroyed when you are finished with it.
00223          */
00224 
00225         spf_request = SPF_request_new(spf_server);
00226 
00227         /* The domain name of the receiving MTA will default to gethostname() */
00228         /* SPF_request_set_rec_dom( spf_request, opt_name ); */
00229         
00230 
00231 /*
00232  * process the SPF request
00233  *
00234  * Now that the SPF system has been configured, we can process the requests.
00235  * There would normally be a loop around this code or it would be placed
00236  * in a subroutine to be called for each email.
00237  *
00238  * If a single email session sends several emails, you don't need to
00239  * reset the IP address or the HELO domain each time, just change the
00240  * envelope from.
00241  */
00242 
00243         /*
00244          * record the IP address of the client (sending) MTA.
00245          *
00246          * There are other SPF_set_ip*() functionx if you have a structure
00247          * instead of a string.
00248          */
00249 
00250         if ( SPF_request_set_ipv4_str( spf_request, opt_ip ) ) {
00251                 printf( "Invalid IP address.\n" );
00252                 res = 255;
00253                 goto error;
00254         }
00255         
00256 
00257         /*
00258          * record the HELO domain name of the client (sending) MTA from
00259          * the SMTP HELO or EHLO commands
00260          *
00261          * This domain name will be used if the envelope from address is
00262          * null (e.g. MAIL FROM:<>).  This happens when a bounce is being
00263          * sent and, in effect, it is the client MTA that is sending the
00264          * message.
00265          */
00266 
00267         if ( SPF_request_set_helo_dom( spf_request, opt_helo ) ) {
00268                 printf( "Invalid HELO domain.\n" );
00269                 res = 255;
00270                 goto error;
00271         }
00272 
00273         /*
00274          * record the envelope from email address from the SMTP MAIL FROM:
00275          * command.
00276          */
00277 
00278         if ( SPF_request_set_env_from( spf_request, opt_sender ) ) {
00279                 printf( "Invalid envelope from address.\n" );
00280                 res = 255;
00281                 goto error;
00282         }
00283 
00284         /*
00285          * now that we have all the information, see what the result of
00286          * the SPF check is.
00287          */
00288 
00289         SPF_request_query_mailfrom(spf_request, &spf_response);
00290 
00291         /*
00292          * If the sender MAIL FROM check failed, then for each SMTP RCPT TO
00293          * command, the mail might have come from a secondary MX for that
00294          * domain.
00295          *
00296          * Note that most MTAs will also check the RCPT TO command to make sure
00297          * that it is ok to accept. This SPF check won't give a free pass
00298          * to all secondary MXes from all domains, just the one specified by
00299          * the rcpt_to address. It is assumed that the MTA checks (at some
00300          * point) that we are also a valid primary or secondary for the domain.
00301          */
00302         if (SPF_response_result(spf_response) != SPF_RESULT_PASS) {
00303                 SPF_request_query_rcptto(spf_request, &spf_response_2mx, opt_rcpt_to);
00304                 /*
00305                  * We might now have a PASS if the mail came from a client which
00306                  * is a secondary MX from the domain specified in opt_rcpt_to.
00307                  *
00308                  * If not, then the RCPT TO: address must have been a domain for
00309                  * which the client is not a secondary MX, AND the MAIL FROM: domain
00310                  * doesn't doesn't return 'pass' from SPF_result()
00311                  */
00312                 if (SPF_response_result(spf_response_2mx) == SPF_RESULT_PASS) {
00313                 }
00314         }
00315 
00316         /*
00317          * If the result is something like 'neutral', you probably
00318          * want to accept the email anyway, just like you would
00319          * when SPF_result() returns 'neutral'.
00320          *
00321          * It is possible that you will completely ignore the results
00322          * until the SMPT DATA command.
00323          */
00324 
00325         if ( opt_debug > 0 ) {
00326                 printf ( "result = %s (%d)\n",
00327                         SPF_strresult(SPF_response_result(spf_response)),
00328                                 SPF_response_result(spf_response));
00329                 printf ( "err = %s (%d)\n",
00330                         SPF_strerror(SPF_response_errcode(spf_response)),
00331                                 SPF_response_errcode(spf_response));
00332                 for (i = 0; i < SPF_response_messages(spf_response); i++) {
00333                         SPF_error_t     *err = SPF_response_message(spf_response, i);
00334                         printf ( "%s_msg = (%d) %s\n",
00335                                 (SPF_error_errorp(err) ? "warn" : "err"),
00336                                 SPF_error_code(err),
00337                                 SPF_error_message(err));
00338                 }
00339         }
00340 
00341 #define VALID_STR(x) (x ? x : "")
00342 
00343         printf( "%s\n%s\n%s\n%s\n",
00344                 SPF_strresult( SPF_response_result(spf_response) ),
00345                 VALID_STR(SPF_response_get_smtp_comment(spf_response)),
00346                 VALID_STR(SPF_response_get_header_comment(spf_response)),
00347                 VALID_STR(SPF_response_get_received_spf(spf_response))
00348                 );
00349 
00350         res = SPF_response_result(spf_response);
00351 
00352 
00353         /*
00354          * The response from the SPF check contains malloced data, so
00355          * make sure we free it.
00356          */
00357 
00358         SPF_response_free(spf_response);
00359         if (spf_response_2mx)
00360                 SPF_response_free(spf_response_2mx);
00361 
00362   error:
00363 
00364         /*
00365          * the SPF configuration variables contain malloced data, so we
00366          * have to vfree them also.
00367          */
00368 
00369         if (spf_request)
00370                 SPF_request_free(spf_request);
00371         if (spf_server)
00372                 SPF_server_free(spf_server);
00373         return res;
00374 }

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4