/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of either:
*
* a) The GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1, or (at your option) any
* later version,
*
* OR
*
* b) The two-clause BSD license.
*
* These licenses can be found with the distribution in the file LICENSES
*/
#ifndef INC_SPF_INTERNAL
#define INC_SPF_INTERNAL
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
#define array_elem(x) ((long int)(sizeof( x ) / sizeof( *x )))
/*
* SPF configuration data
*/
typedef struct
{
/*
* user settable options
*/
int client_ver; /* AF_INET/AF_INET6 */
struct in_addr ipv4; /* client (sending) MTA IP addr */
struct in6_addr ipv6; /* client (sending) MTA IP addr */
char *env_from; /* envelope-from/MAIL FROM: */
char *helo_dom; /* domain name from HELO cmd */
char *rec_dom; /* receiving MTA domain name */
char *rcpt_to_dom; /* RCPT TO: domain for 2mx */
int found_2mx; /* RCPT TO: for 2mx found */
int found_non_2mx; /* RCPT TO: not for 2mx found */
SPF_output_t output_2mx; /* msg to return at DATA time */
int max_dns_mech; /* DoS limit on SPF mechanisms */
int max_dns_ptr; /* DoS limit on PTR records */
int max_dns_mx; /* DoS limit on MX records */
int sanitize; /* limit charset in messages */
int debug; /* print debug info */
/* must be assigned last because compiling uses the config */
SPF_c_results_t local_policy; /* local policies */
SPF_c_results_t exp; /* explanation string */
/*
* synthesized from the above input values
*/
char *lp_from; /* local part of env_from */
/* char *env_from; */
char *dp_from; /* domain part of env_from */
char *cur_dom; /* "current domain" per SPF spec*/
/* struct in_addr *ip; */
/* time_t time; */ /* current time */
char *client_dom; /* verified domain from client IP */
/* char *helo_dom; */
/* char *rec_dom; */
size_t max_var_len; /* max strlen of above vars */
} SPF_iconfig_t;
#define SPF_EXP_MOD_NAME "exp-text"
/*
* Compiled SPF record
*/
/*
* The compiled form of the SPF record is as follows:
*
* * A four byte header which contains the version, and information
* about the mechanisms and modifiers
*
* * Mechanism information, repeated once for each mechanism
*
* * A two byte header describing the mechanism
*
* * Data associated with the mechanism. This can be of several forms
*
* * ip4/ip6 have a fixed format data field, cidr length is in
* the mechanism's parm_len field
*
* * Mechanisms that allow a macro-string
*
* * Optional two byte CIDR length structure. (Yes, this is at
* the beginning, rather than at the end.)
*
* * tokenized data description blocks that can be either:
*
* * two byte macro variable description
*
* * two byte string description, followed by the string
*
* * Modifier information, repeated once for each modifier
*
* * two byte header describing the modifier
*
* * name of the modifier
*
* * tokenized data description blocks that can be either:
*
* * two byte macro variable description
*
* * two byte string description, followed by the string
*/
#define SPF_MAX_STR_LEN 255 /* limits on SPF_data_str_t.len, */
/* SPF_mod_t.name_len and */
/* SPF_mod_t.data_len */
#define SPF_MAX_MECH_LEN 511
#define SPF_MAX_MOD_LEN 511
typedef struct
{
unsigned int version: 3; /* SPF spec version number */
unsigned int num_mech: 6; /* number of mechanisms */
unsigned int num_mod: 5; /* number of modifiers */
unsigned int mech_len: 9; /* bytes of compiled data */
unsigned int mod_len: 9; /* bytes of compiled data */
} SPF_rec_header_t;
#define PREFIX_PASS SPF_RESULT_PASS
#define PREFIX_FAIL SPF_RESULT_FAIL
#define PREFIX_SOFTFAIL SPF_RESULT_SOFTFAIL
#define PREFIX_NEUTRAL SPF_RESULT_NEUTRAL
#define PREFIX_UNKNOWN SPF_RESULT_UNKNOWN
/*
* Mechanisms
*/
#define MECH_A 1
#define MECH_MX 2
#define MECH_PTR 3
#define MECH_INCLUDE 4
#define MECH_IP4 5
#define MECH_IP6 6
#define MECH_EXISTS 7
#define MECH_ALL 8
#define MECH_REDIRECT 9
# if defined( WORDS_BIGENDIAN )
struct SPF_mech_struct
{
unsigned int prefix_type: 3;
unsigned int mech_type: 4;
unsigned int parm_len: 9; /* bytes of data or cidr len */
} __attribute__ ((packed)); /* FIXME: remove packed */
# elif !defined( WORDS_BIGENDIAN )
struct SPF_mech_struct
{
unsigned int mech_type: 4;
unsigned int prefix_type: 3;
unsigned int parm_len: 9; /* bytes of data or cidr len */
} __attribute__ ((packed)); /* FIXME: remove packed */
# else
# error "Adjust your <bits/endian.h> defines"
# endif
typedef struct SPF_mech_struct SPF_mech_t;
#define NETWORK_SIZEOF_MECH_T 2 /* network format */
/*
* Modifiers
*/
typedef struct {
unsigned char name_len;
unsigned char data_len;
} SPF_mod_t;
#define NETWORK_SIZEOF_MOD_T 2 /* network format */
/*
* Optional data to mech/mod
*/
#define PARM_LP_FROM 0 /* l = local-part of envelope-sender */
#define PARM_ENV_FROM 1 /* s = envelope-sender */
#define PARM_DP_FROM 2 /* o = envelope-domain */
#define PARM_CUR_DOM 3 /* d = current-domain */
#define PARM_CLIENT_IP 4 /* i = SMTP client IP */
#define PARM_CLIENT_IP_P 5 /* c = SMTP client IP (pretty) */
#define PARM_TIME 6 /* t = time in UTC epoch secs */
#define PARM_CLIENT_DOM 7 /* p = SMTP client domain name */
#define PARM_CLIENT_VER 8 /* v = IP ver str - in-addr/ip6 */
#define PARM_HELO_DOM 9 /* h = HELO/EHLO domain */
#define PARM_REC_DOM 10 /* r = receiving domain */
#define PARM_CIDR 11 /* CIDR lengths (IPv4 and v6) */
#define PARM_STRING 12 /* literal string */
# if defined( WORDS_BIGENDIAN )
struct SPF_data_str_struct
{
unsigned int parm_type: 4;
unsigned int reserved: 4;
unsigned int len: 8;
} __attribute__ ((packed)); /* FIXME: remove packed */
# elif !defined( WORDS_BIGENDIAN )
struct SPF_data_str_struct
{
unsigned int reserved: 4;
unsigned int parm_type: 4;
unsigned int len: 8;
} __attribute__ ((packed)); /* FIXME: remove packed */
# else
# error "Adjust your <bits/endian.h> defines"
# endif
typedef struct SPF_data_str_struct SPF_data_str_t;
#define NETWORK_SIZEOF_DATA_STR_T 2 /* network format */
# if defined( WORDS_BIGENDIAN )
struct SPF_data_var_struct
{
unsigned int parm_type: 4;
unsigned int num_rhs: 4; /* chop subdomai name */
unsigned int rev: 1; /* reverse */
unsigned int url_encode: 1; /* do URL encoding */
unsigned int delim_dot: 1; /* delimiter char: . */
unsigned int delim_dash: 1; /* delimiter char: - */
unsigned int delim_plus: 1; /* delimiter char: + */
unsigned int delim_equal: 1; /* delimiter char: = */
unsigned int delim_bar: 1; /* delimiter char: | */
unsigned int delim_under: 1; /* delimiter char: _ */
} __attribute__ ((packed)); /* FIXME: remove packed */
# elif !defined( WORDS_BIGENDIAN )
struct SPF_data_var_struct
{
unsigned int num_rhs: 4;
unsigned int parm_type: 4;
unsigned int delim_under: 1;
unsigned int delim_bar: 1;
unsigned int delim_equal: 1;
unsigned int delim_plus: 1;
unsigned int delim_dash: 1;
unsigned int delim_dot: 1;
unsigned int url_encode: 1;
unsigned int rev: 1;
} __attribute__ ((packed)); /* FIXME: remove packed */
# else
# error "Adjust your <bits/endian.h> defines"
# endif
typedef struct SPF_data_var_struct SPF_data_var_t;
#define NETWORK_SIZEOF_DATA_VAR_T 2 /* network format */
# if defined( WORDS_BIGENDIAN )
struct SPF_data_cidr_struct
{
unsigned int parm_type: 4;
unsigned int ipv4: 5;
unsigned int ipv6: 7;
} __attribute__ ((packed)); /* FIXME: remove packed */
# elif !defined( WORDS_BIGENDIAN )
struct SPF_data_cidr_struct
{
unsigned int ipv4: 5;
unsigned int parm_type: 4;
unsigned int ipv6: 7;
} __attribute__ ((packed)); /* FIXME: remove packed */
# else
# error "Adjust your <bits/endian.h> defines"
# endif
typedef struct SPF_data_cidr_struct SPF_data_cidr_t;
#define NETWORK_SIZEOF_DATA_CIDR_T 2 /* network format */
typedef union
{
SPF_data_var_t dv;
SPF_data_str_t ds;
SPF_data_cidr_t dc;
} SPF_data_t;
#define NETWORK_SIZEOF_DATA_T 2 /* network format */
/*
* Compiled SPF records as used internally by libspf-alt
*/
typedef struct
{
SPF_rec_header_t header;
SPF_mech_t *mech_first; /* buffer for mechanisms */
SPF_mech_t *mech_last;
size_t mech_buf_len; /* malloc'ed size */
size_t mech_len; /* used size (non-network format) */
SPF_mod_t *mod_first; /* buffer for modifiers */
SPF_mod_t *mod_last;
size_t mod_buf_len; /* malloc'ed size */
size_t mod_len; /* used size (non-network format) */
} SPF_internal_t;
/*
* misc macros to make the code look cleaner than it really is
*/
#ifndef SPF_MAX_DNS_MECH
/* It is a bad idea to change this for two reasons.
*
* First, the obvious reason is the delays caused on the mail server
* you are running. DNS lookups that timeout can be *very* time
* consuming, and even successful DNS lookups can take 200-500ms.
* Many MTAs can't afford to wait long and even 2sec is pretty bad.
*
* The second, and more important reason, is the SPF records come from
* a third party which may be malicious. This third party can direct
* DNS lookups to be sent to anyone. If there isn't a limit, then it
* is easy for someone to create a distributed denial of service
* attack simply by sending a bunch of emails. Unlike the delays on
* your system caused by many DNS lookups, you might not even notice
* that you are being used as part of a DDoS attack.
*/
#define SPF_MAX_DNS_MECH 10
#endif
#ifndef SPF_MAX_DNS_PTR
/* It is a bad idea to change this for the same reasons as mentioned
* above for SPF_MAX_DNS_MECH
*/
#define SPF_MAX_DNS_PTR 5
#endif
#ifndef SPF_MAX_DNS_MX
/* It is a bad idea to change this for the same reasons as mentioned
* above for SPF_MAX_DNS_MECH
*/
#define SPF_MAX_DNS_MX 5
#endif
static inline SPF_internal_t *SPF_id2spfi( SPF_id_t spfid )
{ return (SPF_internal_t *)spfid; }
static inline SPF_id_t SPF_spfi2id( SPF_internal_t *spfi )
{ return (SPF_id_t)spfi; }
static inline SPF_iconfig_t *SPF_cid2spfic( SPF_config_t spfcid )
{ return (SPF_iconfig_t *)spfcid; }
static inline SPF_config_t SPF_spfic2cid( SPF_iconfig_t *spfic )
{ return (SPF_config_t)spfic; }
/* FIXME: need to make these network/compiler portable */
static inline size_t SPF_mech_data_len( SPF_mech_t * mech )
{ return (mech->mech_type == MECH_IP4) ? sizeof( struct in_addr ) : (mech->mech_type == MECH_IP6) ? sizeof( struct in6_addr ) : mech->parm_len; }
static inline SPF_mech_t *SPF_next_mech( SPF_mech_t * mech )
{ return (SPF_mech_t *)( (char *)mech + sizeof(SPF_mech_t) + SPF_mech_data_len( mech ));}
static inline SPF_data_t *SPF_mech_data( SPF_mech_t *mech )
{ return (SPF_data_t *)( (char *)mech + sizeof(SPF_mech_t)); }
static inline SPF_data_t *SPF_mech_end_data( SPF_mech_t *mech )
{ return (SPF_data_t *)( (char *)SPF_next_mech(mech)); }
static inline struct in_addr *SPF_mech_ip4_data( SPF_mech_t *mech )
{ return (struct in_addr *)( (char *)mech + sizeof(SPF_mech_t)); }
static inline struct in6_addr *SPF_mech_ip6_data( SPF_mech_t *mech )
{ return (struct in6_addr *)( (char *)mech + sizeof(SPF_mech_t)); }
static inline SPF_data_t *SPF_next_data( SPF_data_t *data )
{ return (SPF_data_t *)( (char *)data + sizeof(SPF_data_t) + (data->ds.parm_type == PARM_STRING ? data->ds.len : 0)); }
static inline char *SPF_data_str( SPF_data_t *data )
{ return (char *)data + sizeof(SPF_data_t); }
static inline SPF_mod_t *SPF_next_mod( SPF_mod_t *mod )
{ return (SPF_mod_t *)( (char *)mod + sizeof(SPF_mod_t) + mod->name_len + mod->data_len); }
static inline char *SPF_mod_name( SPF_mod_t *mod )
{ return (char *)mod + sizeof(SPF_mod_t); }
static inline SPF_data_t *SPF_mod_data( SPF_mod_t *mod )
{ return (SPF_data_t *)((char *)mod + sizeof(SPF_mod_t) + mod->name_len); }
static inline SPF_data_t *SPF_mod_end_data( SPF_mod_t *mod )
{ return (SPF_data_t *)((char *)SPF_mod_data(mod) + mod->data_len); }
SPF_err_t SPF_expand( SPF_config_t spfcid, SPF_dns_config_t spfdc,
SPF_data_t *data, size_t data_len,
char **buf, size_t *buf_len);
SPF_err_t SPF_find_mod_data( SPF_config_t spfcid, SPF_id_t spfid, const char *mod_name,
SPF_data_t **data, size_t *data_len );
SPF_err_t SPF_data2str( char **p_p, char *p_end,
SPF_data_t *data, SPF_data_t *data_end,
int is_mech, int cidr_ok );
char *SPF_sanitize( SPF_config_t spfcid, char *str );
int SPF_is_loopback( SPF_config_t spfcid );
static inline unsigned int SPF_c2ui( char c ) {return (unsigned int)c;}
void SPF_print_sizeof(void);
SPF_err_t SPF_c_mech_add( SPF_id_t spfid, int mech_type, int prefix );
SPF_err_t SPF_c_mech_data_add( SPF_id_t spfid, char const **p_p, char const **p_token, int cidr_ok );
SPF_err_t SPF_c_mech_ip4_add( SPF_id_t spfid, char const **p_p, char const **p_token );
SPF_err_t SPF_c_mech_ip6_add( SPF_id_t spfid, char const **p_p, char const **p_token );
SPF_err_t SPF_c_mod_add( SPF_id_t spfid, const char *mod_name, size_t name_len );
SPF_err_t SPF_c_mod_data_add( SPF_id_t spfid, char const **p_p, char const **p_token, int cidr_ok );
int SPF_mech_cidr( SPF_config_t spfcid, SPF_mech_t *mech );
int SPF_ip_match( SPF_config_t spfcid, SPF_mech_t *mech,
struct in_addr ipv4 );
int SPF_ip_match6( SPF_config_t spfcid, SPF_mech_t *mech,
struct in6_addr ipv6 );
#endif
syntax highlighted by Code2HTML, v. 0.9.1