/* * spf_example - An example program for how to use libspf-alt * * Author: Wayne Schlitt * * File: spfquery.c * Desc: SPF command line utility * * * This program is in the public domain, there is no copyright, you * can do anything you want with it. */ /* * The libspf-alt library uses the GNU autoconf system to help make * the library more portable. The config.h file should have the * HAVE_xxx defines that are appropriate for your system. Either use * autconf to create it, or create it by hand. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include /* malloc / free */ #endif #ifdef HAVE_SYS_TYPES_H #include /* types (u_char .. etc..) */ #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_STRING_H # include /* strstr / strdup */ #else # ifdef HAVE_STRINGS_H # include /* strstr / strdup */ # endif #endif #ifdef HAVE_SYS_SOCKET_H # include /* inet_ functions / structs */ #endif #ifdef HAVE_NETINET_IN_H # include /* inet_ functions / structs */ #endif #ifdef HAVE_ARPA_INET_H # include /* in_addr struct */ #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_GETOPT_H #include #endif /* * libspf-alt public include files that are needed for this example * program */ #include "spf.h" #include "spf_dns_resolv.h" #include "spf_dns_cache.h" /* * usage() just prints out the command line options for this program */ static void usage() { fprintf( stderr, "Usage:\n" "\n" "spf_example [options]\n" "\n" "Valid data options are:\n" " -i The IP address that is sending email\n" " -s The email address used as the\n" " envelope-from. If no username (local\n" " part) is given, 'postmaster' will be\n" " assumed.\n" " -h The domain name given on the SMTP HELO\n" " command. This is only needed if the\n" " -sender option is not given.\n" " -debug [debug level] debug level.\n" ); } /* * All the code is in the main routine, but most usages of libspf-alt * would have the code spread around into various subrotines. */ int main( int argc, char *argv[] ) { int c; int res = 0; char *opt_ip = NULL; char *opt_sender = NULL; char *opt_helo = NULL; int opt_debug = 0; SPF_config_t spfcid = NULL; SPF_dns_config_t spfdcid_resolv = NULL; SPF_dns_config_t spfdcid = NULL; SPF_output_t spf_output; /* * check the arguments */ while (1) { c = getopt(argc, argv, "i:s:h:d::" ); if (c == -1) break; switch (c) { case 'i': opt_ip = optarg; break; case 's': opt_sender = optarg; break; case 'h': opt_helo = optarg; break; case 0: case '?': usage(); res = 255; goto error; break; case 'd': if (optarg == NULL) opt_debug = 1; else opt_debug = atoi( optarg ); break; default: fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c); } } if (optind != argc || opt_ip == NULL || (opt_helo == NULL && opt_sender == NULL)) { usage(); res = 255; goto error; } /* * Configure the SPF system. * * libspf-alt is designed so that configurations can be set up once * and reused many times different emails delivered in a single SMTP * session or in different SMTP sessions. */ /* * set up the SPF configuration * * The SPF configuration contains all the data needed to process * the SPF check. Configurations contain malloc so it must be * destroyed when you are finished with it. In a multi-threaded * environment, you need one per thread. */ spfcid = SPF_create_config(); if ( spfcid == NULL ) { fprintf( stderr, "SPF_create_config failed.\n" ); res = 255; goto error; } SPF_set_debug( spfcid, opt_debug ); /* The domain name of the receiving MTA will default to gethostname() */ /* SPF_set_rec_dom( spfcid, opt_name ); */ /* * set up dns layers to use * * The SPF DNS configuration layers contains data needed to do the * DNS lookups and to return the results. Configurations contain * malloc so it must be destroyed when you are finished with * it. In a multi-threaded environment, you need one per thread. * * Even a small DNS cache can reduce the CPU usage compared with * even a local caching name server. */ spfdcid_resolv = SPF_dns_create_config_resolv( NULL, opt_debug ); spfdcid = SPF_dns_create_config_cache( spfdcid_resolv, 8, opt_debug ); /* * process the SPF request * * Now that the SPF system has been configured, we can process the requests. * There would normally be a loop around this code or it would be placed * in a subroutine to be called for each email. * * If a single email session sends several emails, you don't need to * reset the IP address or the HELO domain each time, just change the * envelope from. */ /* * record the IP address of the client (sending) MTA. * * There are other SPF_set_ip*() functionx if you have a structure * instead of a string. */ if ( SPF_set_ip_str( spfcid, opt_ip ) ) { printf( "Invalid IP address.\n" ); res = 255; goto error; } /* * record the HELO domain name of the client (sending) MTA from * the SMTP HELO or EHLO commands * * This domain name will be used if the envelope from address is * null (e.g. MAIL FROM:<>). This happens when a bounce is being * sent and, in effect, it is the client MTA that is sending the * message. */ if ( SPF_set_helo_dom( spfcid, opt_helo ) ) { printf( "Invalid HELO domain.\n" ); res = 255; goto error; } /* * record the envelope from email address from the SMTP MAIL FROM: * command. */ if ( SPF_set_env_from( spfcid, opt_sender ) ) { printf( "Invalid envelope from address.\n" ); res = 255; goto error; } /* * now that we have all the information, see what the result of * the SPF check is. */ spf_output = SPF_result( spfcid, spfdcid ); if ( opt_debug > 0 ) { printf ( "result = %s (%d)\n", SPF_strresult( spf_output.result ), spf_output.result ); printf ( "err = %s (%d)\n", SPF_strerror( spf_output.err ), spf_output.err ); printf ( "err_msg = %s\n", spf_output.err_msg ? spf_output.err_msg : "" ); } printf( "%s\n%s\n%s\n%s\n", SPF_strresult( spf_output.result ), spf_output.smtp_comment ? spf_output.smtp_comment : "", spf_output.header_comment ? spf_output.header_comment : "", spf_output.received_spf ? spf_output.received_spf : "" ); res = spf_output.result; /* * the ouput from the SPF check contains malloced data, so make sure * we free it. */ SPF_free_output( &spf_output ); error: /* * the SPF configuration variables contain malloced data, so we * have to vfree them also. */ if ( spfcid ) SPF_destroy_config( spfcid ); if ( spfdcid ) SPF_dns_destroy_config_cache( spfdcid ); if ( spfdcid_resolv ) SPF_dns_destroy_config_resolv( spfdcid_resolv ); SPF_destroy_default_config(); return res; }