spfqtool.c

    /* libspf - Sender Policy Framework library
    *
    *  ANSI C implementation of spf-draft-200405.txt
    *
    *  Author: James Couzens <jcouzens@codeshare.ca>
    *
    *  File:   spfqtool.c
    *  Desc:   SPF Query Tool (an example implementation of libSPF)
    *
    *  License:
    *
    *  The libspf Software License, Version 1.0
    *
    *  Copyright (c) 2004 James Couzens & Sean Comeau  All rights
    *  reserved.
    *
    *  Redistribution and use in source and binary forms, with or without
    *  modification, are permitted provided that the following conditions
    *  are met:
    *
    *  1. Redistributions of source code must retain the above copyright
    *     notice, this list of conditions and the following disclaimer.
    *
    *  2. Redistributions in binary form must reproduce the above copyright
    *     notice, this list of conditions and the following disclaimer in
    *     the documentation and/or other materials provided with the
    *     distribution.
    *
    *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    *  DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS MAKING USE OF THIS LICESEN
    *  OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    *  SUCH DAMAGE.
    *
    */

    #include "spfqtool.h"

    /* SPF_usage
    *
    *  Author: James Couzens <jcouzens@6o4.ca>
    *
    *  Date:   07/04/04
    *  Date:   07/28/04 - Renamed to spfqtool
    *  Date:   09/08/04 - Added SPF_build_header call
    *
    *  Desc:
    *         Main function, allocates memory and makes calls to the libSPF
    *  library which parses the "fake" query.
    *
    */
    int main(int argc, char *argv[])
    {
      u_int8_t i = 0;                      /* utility */

      SPF_RESULT res = SPF_UNKNOWN;        /* libSPF result code */

      SPF_BOOL use_explain = SPF_FALSE;    /* T / F provide SPF Explanation */
      SPF_BOOL use_trusted = SPF_FALSE;    /* T / F attempt Trusted Forwarder */
      SPF_BOOL use_guess   = SPF_FALSE;    /* T / F attempt Best Guess */
      SPF_BOOL test_mode   = SPF_FALSE;    /* T / F enable test mode */

      char *margv   = NULL;                /* pointer to current argv element */
      char *ip      = NULL;                /* ip address to test connecting from */
      char *address = NULL;                /* email address to test sending from */
      char *helo    = NULL;                /* helo hostname to test sending from */
      char *tmp     = NULL;                /* utility pointer */
      char *buf     = NULL;                /* buffer to store generated SPF header */

      peer_info_t *pinfo = NULL;           /* libSPF peer_info structure */

      if (argc <= 1)
      {
        SPF_usage();

        return(SPF_FALSE);
      }

      for (i = 1; i < argc; i++)
      {
        tmp = argv[i];

        if (*tmp == '-')
        {
          margv = (tmp + 3);

          switch (*(tmp + 1))
          {
            /* best guess */
            case 'b' :
            {
              use_guess = atoi(margv);

              break;
            } /* 'b' */

            /* debug */
            case 'd' :
            {
              confg.level = atoi(margv);

              break;
            } /* 'd' */

            /* explanation */
            case 'e' :
            {
              use_explain = atoi(margv);

              break;
            } /* 'e' */

            /* RFC2821 HELO */
            case 'h' :
            {
              helo  = strdup(margv);

              break;
            } /* 'h' */

            /* ip address */
            case 'i' :
            {
              ip  = strdup(margv);

              break;
            } /* 'i' */

            /* source email address */
            case 's' :
            {
              address = strdup(margv);

              break;
            } /* 's' */

            /* trusted forwarder */
            case 't' :
            {
              use_trusted = atoi(margv);

              break;
            } /* 't' */

            /* version */
            case 'v' :
            {
              printf("SPF Query Tool v%s - James Couzens <jcouzens@codeshare.ca>\n\n",
                SPFQTOOL_VERSION);

              return(0);
            } /* 'v' */

            /* test mode */
            case 'z' :
            {
              test_mode = SPF_TRUE;

              break;
            } /* 'z' */

            default:
            {
              break;
            } /* default */
          }
        }
      } /* for */

      if (ip == NULL)
      {
        printf("You need to specify an IP Address to test against\n\n");

        SPF_usage();

        free(address);

        return(SPF_FALSE);
      }
      else if (address == NULL)
      {
        printf("You need to specify a from email address\n\n");

        SPF_usage();

        free(ip);

        return(SPF_FALSE);
      }
      else if (helo == NULL)
      {
        helo = strdup(HELO_HOST);

        printf("You didn't give me a helo host, using (%s)\n", helo);
      }

      if (confg.level >= 1)
      {
        printf("SPF Query Tool v%s - James Couzens <jcouzens@codeshare.ca>\n",
          SPFQTOOL_VERSION);

        printf("[DEBUG]: Debugging level:    %u\n", confg.level);
        printf("[DEBUG]: RFC2821 Mail From:  %s\n", address);
        printf("[DEBUG]: RFC2821 HELO:       %s\n", helo);
        printf("[DEBUG]: Purported address:  %s\n", ip);

        printf("[DEBUG]: SPF Explanation:    %s\n",
          use_explain ? "Enabled" : "Disabled");

        printf("[DEBUG]: Trusted Forwarder:  %s\n",
          use_trusted ? "Enabled" : "Disabled");

        printf("[DEBUG]: Best Guess:         %s\n",
          use_guess ? "Enabled" : "Disabled");

        printf("\n");
      }

      if ((pinfo = SPF_init(helo, ip, NULL, NULL, NULL,
                            use_trusted, use_guess)) != NULL)
      {
        /* perform fake HELO */
        SPF_smtp_helo(pinfo, helo);

        /* perform fake MAIL FROM */
        SPF_smtp_from(pinfo, address);

        /* assign and perform SPF parse */
        res = pinfo->RES = SPF_policy_main(pinfo);

        /* print the results of the query.  The NULL check on the output is
         * to the benefit of SOLARIS users where printf is unable to handle
         * a NULL variable.  Linux users can omit this check.
         */

        if (test_mode != SPF_TRUE)
        {
          printf("SPF short result:   %s\n",
            pinfo->rs ? pinfo->rs : "NULL");

          printf("SPF verbose result: %s\n",
            pinfo->error ? pinfo->error : "NULL");
        }
        else
        {
          printf("%s\n%s\n%s\n",
            pinfo->rs      ? pinfo->rs      : "NULL",
            pinfo->error   ? pinfo->error   : "NULL",
            pinfo->explain ? pinfo->explain : "NULL");
        }

        if (use_explain == SPF_TRUE)
        {
          buf = SPF_get_explain(pinfo);

          printf("SPF explanation:    %s\n",
            pinfo->explain ? pinfo->explain : "NULL");

          free(buf);
        }

        /* for the tests we need to be silent :-) */
        if (test_mode != SPF_TRUE)
        {
          if (use_trusted == SPF_TRUE)
          {
            printf("Trusted Forwarder:  Attempted.\n");
          }

          if (use_guess == SPF_TRUE)
          {
            printf("Best Guess:         Attempted.\n");
          }

          if ((buf = SPF_build_header(pinfo)) != NULL)
          {
            printf("RFC2822 header:     %s\n", buf);
            free(buf);
          }
        }

        /* close SPF session (free memory associated with parse) */
        SPF_close(pinfo);
      }

      free(ip);
      free(address);
      free(helo);

      return(SPF_FALSE);
    }

    /* SPF_usage
    *
    *  Author: James Couzens <jcouzens@6o4.ca>
    *
    *  Date:   12/25/03
    *  Date:   07/28/04 - Renamed to spfqtool
    *
    *  Desc:
    *         Displays usage help information when the binary is called with
    *  no arguments.
    *
    */
    void SPF_usage()
    {
      printf("spfqtool usage:\n");
      printf("\n");
      printf("spfqtool [b|d|e|i|s|t|h|v]\n");
      printf("\n");
      printf("-b [0,1]   - Enable Best Guess support (True (0) or False (1))\n");
      printf("-d [x]     - DEBUG where x is a number between 1 and 255\n");
      printf("-e [0,1]   - Enable SPF explanation (True (0) or False (1))\n");
      printf("-h [host]  - HELO hostname to test with\n");
      printf("-i [addr]  - IP Address where the fake connection will come from\n");
      printf("-s [email] - What email address to test with\n");
      printf("-t [0,1]   - Enable Trusted Forwarder support (True (0) or False (1))\n");
      printf("-v         - Display version string\n");
      printf("\n");
      printf("Example: ./spfqtool -i 10.0.0.2 -s jcouzens@6o4.ca -h spftools.net\n");
      printf("\n");
      printf("Minimum required arguments are 'i', and 's'\n");
      printf("\n");

      return;
    }

    /* end spfqtool.c */