/* * spf.h * Copyright(c) 2004, Terence Way (terry@wayforward.net) * * This software is licensed for use with, at your choice: * the GPL (read the file COPYING included in this distribution), or * the Artistic License (read the file LICENSE included in this * distribution. * * Summary: * This API implements a Sender-Permitted From (SPF) query client. * SPF is a mechanism to determine forged SMTP senders. For more * information about SPF, visit the SPF web site at * http://spf.pobox.com * * Table of Contents: * enum spf_result; ..... status of an SPF query * struct spf_cache_entry; internal DNS cache * struct spf_query; .... state of an SPF query * * spf_init(); .......... call before any other function * * spf_query(); ......... high-level blocking query * spf_open(); .......... start a low-level async query * * spf_txt(); ........... give DNS result to SPF query * spf_a(); " * spf_ptr(); " * spf_mx(); " * * spf_check(); ......... check the current status of an SPF query * * spf_close(); ......... release all memory allocated by a query * * Description: * The simplest way to use this API is to call spf_query(): * enum spf_result * spf_query(ipaddr, helo, sender, * received_spf_buffer, buffer_length); * * By the way, the best way to remember the order of the arguments * is: input first, followed by output; the input parameters in the * same order that a mail server would discover them (IP address * first, followed by the HELO/EHLO argument, followed by the MAIL * FROM argument). * * The spf_query() function will make DNS queries until a * definitive answer can be found. * * If you need to multiple many SPF queries, use the low-level API. * First, create a query context: * struct spf_query * spf_open(ipaddr, helo, sender); * * Inside the spf_query structure are the parameters for one or more * DNS queries that you must perform. When these queries are done, * take *ALL* the answers (all the AN, NS, and AR records) and call * the SPF functions appropriate to the record type: * spf_txt(pquery, txt) * spf_a(pquery, ipaddr) * spf_ptr(pquery, name) * spf_mx(pquery, priority, hostname) * * For instance, if there are three TXT records, call spf_txt * three times. * * When the entire DNS response has been eaten, call spf_check(): * enum spf_result * spf_check(pquery, received_spf_buffer, buffer_length) * * This will return spf_incomplete if there are more DNS queries * to do, or will return spf_fail, spf_pass, spf_unknown, or * spf_error when done. If the query is done, a string describing * the result will be written to received_spf_header. This string * includes the 'Received-SPF: ' at the front, and the terminating * CR LF. * * When the query is complete, call spf_close() to free up any * allocated memory. */ #ifndef SPF_H #define SPF_H #ifdef _WIN32 # include # include /* for struct in_addr */ #else # include # include /* for struct in_addr */ #endif #define SPF_API #ifdef __cplusplus extern "C" { #endif enum spf_result { /* query is not complete until more DNS responses arrive */ SPF_INCOMPLETE, /* the mail sender is *NOT* authorized from this host */ SPF_FAIL, /* the mail sender is authorized from this host */ SPF_PASS, /* the correct mail sender host cannot be determined */ SPF_UNKNOWN, /* an error has occurred: usually DNS error */ SPF_ERROR }; struct spf_cache_entry; enum spf_token_type { SPF_EOF = -1, /* modifiers */ SPF_UNKNOWN_MODIFIER = 0, SPF_DEFAULT, SPF_EXP, SPF_REDIRECT, SPF_V, /* add new modifiers here */ SPF_LAST_MODIFIER, /* mechanisms */ SPF_UNKNOWN_MECHANISM = 64, SPF_INVALID_MECHANISM, SPF_A, SPF_ALL, SPF_EXISTS, SPF_INCLUDE, SPF_IP, SPF_MX, SPF_PTR, /* add new mechanisms here */ SPF_LAST_MECHANISM }; struct spf_token { /* enum spf_result */ unsigned char spf_result; /* enum spf_token_type */ signed char spf_type; unsigned char cidr_length; char *value; }; struct spf_query { /* Results of SPF query */ enum spf_result result; char *received_spf; /* Additional DNS queries to perform */ struct { const char *qname; int qtype, qclass; } queries[5]; unsigned nqueries; /* internal information: do not touch! */ /* * current SPF query we're working against * array of tokens terminated by SPF_EOF */ struct spf_token *spf_tokens; /* ptr within spf_tokens, points to SPF_EOF when done */ struct spf_token *spf_current; /* parsed modifiers */ char *spf_exp, *spf_redirect; enum spf_result spf_default; unsigned rl; /* recursion level */ /* macro expansions */ struct in_addr i; /* ip address of SMTP client */ char *s; /* sender declared in MAIL FROM:<> */ char *l; /* local part of sender s */ char *d; /* current domain, initially domain part of sender s */ char *h; /* helo */ const char *v; /* 'in-addr' for IPv4 clients and 'ip6' for IPv6 clients */ char *p; /* SMTP client domain name */ char *o; /* domain part of sender s */ char t[16]; /* current timestamp */ /* DNS cache: hash map from (name, class, type) to data */ struct spf_cache_entry *cache[17]; }; int SPF_API spf_init(void); /* * high-level blocking query * * ipaddr is the incoming IP address of the SMTP client * helo is the string passed by HELO/EHLO ex. "mx1.wayforward.net" * sender is the argument to the MAIL FROM:<> without the angle * brackets, ex. "terry@wayforward.net" * * The result of the query is returned (any spf_result enumerated * value except for spf_incomplete) and the received_spf_buffer is * filled with */ enum spf_result SPF_API spf_query(struct in_addr ipaddr, const char *helo, const char *sender, char *received_spf_buffer, unsigned buffer_length); struct spf_query * SPF_API spf_open(struct in_addr ipaddr, const char *helo, const char *sender); void SPF_API spf_a(struct spf_query *q, const char *name, struct in_addr addr); void SPF_API spf_txt(struct spf_query *q, const char *name, const char *txt); void SPF_API spf_mx(struct spf_query *q, const char *name, int priority, const char *host); void SPF_API spf_ptr(struct spf_query *q, const char *name, const char *host); enum spf_result SPF_API spf_check(struct spf_query *q, char *received_spf_header, unsigned buffer_length); /*********************** * Low-level routines... */ /* low-level tokenizer for utility programs */ enum spf_token_type SPF_API spf_tokenize(struct spf_query *q, char **p, struct spf_token *t); /* Directly set SPF record for overrides, testing */ void SPF_API spf_set_spf_txt(struct spf_query *q, char *spf_text); /* Expand strings containing SPF macros */ size_t SPF_API spf_expand(struct spf_query *q, const char *str, char *buffer, size_t length); /* * ...low-level routines ***********************/ void SPF_API spf_close(struct spf_query *q); #ifdef __cplusplus } #endif #endif /* SPF_H */