1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
|
/*
* spf_example - An example program for how to use libspf2
*
* Author: Wayne Schlitt <wayne@midwestcs.com>
*
* 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 libspf2 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 <stdio.h>
# include <stdlib.h> /* malloc / free */
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h> /* types (u_char .. etc..) */
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h> /* strstr / strdup */
#else
# ifdef HAVE_STRINGS_H
# include <strings.h> /* strstr / strdup */
# endif
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h> /* inet_ functions / structs */
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h> /* inet_ functions / structs */
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h> /* in_addr struct */
#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h> /* DNS HEADER struct */
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
/*
* libspf2 public include files that are needed for this example
* program
*/
#include "spf.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 <IP address> The IP address that is sending email\n"
" -s <email address> The email address used as the\n"
" envelope-from. If no username (local\n"
" part) is given, 'postmaster' will be\n"
" assumed.\n"
" -r <email address> [optional] The email address used as\n"
" the envelope-to email address, for\n"
" secondary-MX checking.\n"
" -h <domain name> The domain name given on the SMTP HELO\n"
" command. This is only needed if the\n"
" -sender option is not given.\n"
" -d [debug level] debug level.\n"
);
}
/*
* All the code is in the main routine, but most usages of libspf2
* would have the code spread around into various subrotines.
*/
int main( int argc, char *argv[] )
{
int c;
int res = 0;
int i;
char *opt_ip = NULL;
char *opt_sender = NULL;
char *opt_helo = NULL;
char *opt_rcpt_to = NULL;
int opt_debug = 0;
/* You should not indirect on any of these structures, as their
* layout may change between versions of the library. Use the
* accessor functions instead. Definitions of the structs may not
* even be provided. */
SPF_server_t *spf_server = NULL;
SPF_request_t *spf_request = NULL;
SPF_response_t *spf_response = NULL;
SPF_response_t *spf_response_2mx = NULL;
/*
* check the arguments
*/
while (1)
{
c = getopt(argc, argv, "i:s:h:r: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 'r':
opt_rcpt_to = 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.
*
* libspf2 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 server
*
* Configurations contain malloc'd data so must be
* destroyed when you are finished.
*/
spf_server = SPF_server_new(SPF_DNS_CACHE, 1);
if (spf_server == NULL) {
fprintf( stderr, "SPF_create_config failed.\n" );
res = 255;
goto error;
}
/*
* Create a new request.
*
* The SPF request contains all the data needed to process
* the SPF check. Requests are malloc'd so it must be
* destroyed when you are finished with it.
*/
spf_request = SPF_request_new(spf_server);
/* The domain name of the receiving MTA will default to gethostname() */
/* SPF_request_set_rec_dom( spf_request, opt_name ); */
/*
* 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_request_set_ipv4_str( spf_request, 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_request_set_helo_dom( spf_request, 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_request_set_env_from( spf_request, 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_request_query_mailfrom(spf_request, &spf_response);
/*
* If the sender MAIL FROM check failed, then for each SMTP RCPT TO
* command, the mail might have come from a secondary MX for that
* domain.
*
* Note that most MTAs will also check the RCPT TO command to make sure
* that it is ok to accept. This SPF check won't give a free pass
* to all secondary MXes from all domains, just the one specified by
* the rcpt_to address. It is assumed that the MTA checks (at some
* point) that we are also a valid primary or secondary for the domain.
*/
if (SPF_response_result(spf_response) != SPF_RESULT_PASS) {
SPF_request_query_rcptto(spf_request, &spf_response_2mx, opt_rcpt_to);
/*
* We might now have a PASS if the mail came from a client which
* is a secondary MX from the domain specified in opt_rcpt_to.
*
* If not, then the RCPT TO: address must have been a domain for
* which the client is not a secondary MX, AND the MAIL FROM: domain
* doesn't doesn't return 'pass' from SPF_result()
*/
if (SPF_response_result(spf_response_2mx) == SPF_RESULT_PASS) {
}
}
/*
* If the result is something like 'neutral', you probably
* want to accept the email anyway, just like you would
* when SPF_result() returns 'neutral'.
*
* It is possible that you will completely ignore the results
* until the SMPT DATA command.
*/
if ( opt_debug > 0 ) {
printf ( "result = %s (%d)\n",
SPF_strresult(SPF_response_result(spf_response)),
SPF_response_result(spf_response));
printf ( "err = %s (%d)\n",
SPF_strerror(SPF_response_errcode(spf_response)),
SPF_response_errcode(spf_response));
for (i = 0; i < SPF_response_messages(spf_response); i++) {
SPF_error_t *err = SPF_response_message(spf_response, i);
printf ( "%s_msg = (%d) %s\n",
(SPF_error_errorp(err) ? "warn" : "err"),
SPF_error_code(err),
SPF_error_message(err));
}
}
#define VALID_STR(x) (x ? x : "")
printf( "%s\n%s\n%s\n%s\n",
SPF_strresult( SPF_response_result(spf_response) ),
VALID_STR(SPF_response_get_smtp_comment(spf_response)),
VALID_STR(SPF_response_get_header_comment(spf_response)),
VALID_STR(SPF_response_get_received_spf(spf_response))
);
res = SPF_response_result(spf_response);
/*
* The response from the SPF check contains malloced data, so
* make sure we free it.
*/
SPF_response_free(spf_response);
if (spf_response_2mx)
SPF_response_free(spf_response_2mx);
error:
/*
* the SPF configuration variables contain malloced data, so we
* have to vfree them also.
*/
if (spf_request)
SPF_request_free(spf_request);
if (spf_server)
SPF_server_free(spf_server);
return res;
}
|