slow.h #5

  • //
  • guest/
  • bryan_costales/
  • slow.h
  • View
  • Commits
  • Open Download .zip Download (12 KB)
/***********************************************************
* Tune the slowmilter program
*
* $Id: slow.h,v 1.8 2003/12/15 15:03:33 bcx Exp bcx $
*
* Copyright Bryan Costales 2003
* Placed into the pubic domain 2003
***********************************************************/

# ifdef HAVE_CONFIG_H
# include "config.h"
# else
	Error: config.h required.
# endif

# if HAVE_CTYPE_H
#	include <ctype.h>
# endif
# if HAVE_ERRNO_H
#	include <errno.h>
# endif
# if HAVE_FCNTL_H
#	include <fcntl.h>
# endif
# ifdef sun
#	include <libgen.h>
# endif
# if HAVE_MEMORY_H
#	include <memory.h>
# endif
# if HAVE_STDIO_H
#	 include <stdio.h>
# endif
# if HAVE_STDLIB_H
#	include <stdlib.h>
# endif
# if HAVE_STRING_H
#	include <string.h>
# endif
# if HAVE_SYS_SOCKET_H
#	include <sys/socket.h>
# endif
# if HAVE_SYS_STAT_H
#	include <sys/stat.h>
# endif
# if HAVE_SYS_TYPES_H
#	include <sys/types.h>
# endif
# if HAVE_SYSEXITS_H
#	include <sysexits.h>
# endif
# if HAVE_SYSLOG_H
#	include <syslog.h>
# endif
# if TM_IN_SYS_TIME
#	include <sys/time.h>
# else
#	include <time.h>
# endif
# if TIME_WITH_SYS_TIME && TM_IN_SYS_TIME
#	include <time.h>
# endif
# if HAVE_UNISTD_H
#	include <unistd.h>
# endif
# if HAVE_NETDB_H
#	include <netdb.h>
# endif
# if HAVE_NETINET_IN_H
#	include <netinet/in.h>
# endif
# if HAVE_SYS_PARAM_H
#	include <sys/param.h>
# endif
# if HAVE_ARPA_INET_H
#	include <arpa/inet.h>
# endif
# if HAVE_ARPA_NAMESER_H
#	include <arpa/nameser.h>
# endif
# if HAVE_REGEX_H
# 	include <regex.h>
# endif
# if HAVE_PTHREAD_H
#	include <pthread.h>
# endif

# include <resolv.h>
# include <db.h>
# include <libmilter/mfapi.h>

# ifndef TRUE
#       define TRUE (1) 
# endif
# ifndef FALSE 
#       define FALSE (0)
# endif 
# define bool int

/********************************************************
** Definitions used for MX lookups.
*/
# define MAXMXHOSTS 100
# ifndef HFIXEDSZ
#	define HFIXEDSZ 12	/* sizeof(HEADER) */
# endif
typedef union
{
	HEADER  qb1;
	u_char  qb2[PACKETSZ];
} QBUF;

# ifndef INT16SZ
#	define INT16SZ  2
# endif
# ifndef INT32SZ
#	define INT32SZ 4
# endif
# ifndef MAXHOSTNAMELEN
#	define MAXHOSTNAMELEN 128
# endif
# if defined(__RES) && (__RES >= 19940415)
#	define RES_UNC_T      char *
# else
#	define RES_UNC_T      u_char *
# endif

EXTERN char **MxHosts;
EXTERN char *LocalHostName;
EXTERN bool Verbose;

/********************************************************
** Definition of the Database keys and data.
*/

/* 
 * This defines what is stored in the database. 
 * Be sure to bump the version when you add new items
 * to the SECONDARY_DATUM below.
 */
# define DBVERSION 1
EXTERN time_t DBVersion;

typedef unsigned long BITMAP;
# define isbitset(bit, word) (((word) & (bit)) != 0)
# define set_bit(bit, word) ((word) |= (bit))

# define DATABASE_VERSION 	(1)	/* first datum is a flag */
/*
 * The primary database has binary IP numbers as keys.
 * IP==0 is special because its data is the version of the database.
 * The data is an array of dates in unix time_t format.
 */
typedef unsigned long     PRIMARY_KEY;	/* IPv4 IP number in numeric binary */
typedef time_t	     PRIMARY_DATUM;	/* A unit of date/time in binary */
typedef PRIMARY_DATUM **PRIMARY_DATA;	/* FIFO list of date/times */

/*
 * The secondary database has a combined key made up of an IP number
 * and a time_t date. That combined key documents a single event.
 * The data is a SECONDARY_DATUM structure (see below).
 */
typedef struct {
	PRIMARY_KEY	ip;
	PRIMARY_DATUM	date;
} SECONDARY_KEY;

# define MAX_MESSAGE_ID (256)
typedef struct {
	BITMAP		eventmap;	/* See the BIT_ definitions below */
	unsigned int	envrcpts;	/* excess envelope recipients */
	unsigned int	headrcpts;	/* excess header recipients */
	unsigned int	honeyrcpts;	/* total honey pot recipients */
	unsigned int	badrcpts;	/* total bad recipients */
	char            msgid[MAX_MESSAGE_ID];
} SECONDARY_DATUM;


/********************************************************
** Should we log? And if so, how?
*/
EXTERN bool DoLog;
EXTERN bool LogEvents;
EXTERN char *LogPrefix;

/********************************************************
** Types of special dadabase records. Must not be zero
** nor greater than MAX_TYPE_RECORD.
*/
# define TYPE_RECORD_WHITELIST 	(1)	/* whitelisted IP */
# define TYPE_RECORD_ALIAS 	(2)	/* See actual IP */
# define MAX_TYPE_RECORD	(255)

/********************************************************
** Debugging and regression testiong.
*/
EXTERN unsigned int Debugbits;
# define isdebug(tok) isbitset(tok, Debugbits)
# define anydebug() (Debugbits != 0)
# define BUG_MX          (0x00000001) /* debug bitmap */
# define BUG_DB          (0x00000002) /* debug bitmap */
# define BUG_PUSHN       (0x00000004) /* debug bitmap */ 
# define BUG_XXX         (0x00000008) /* debug bitmap */  /* unused */
# define BUG_SOURCE	 (0x00000010) /* debug bitmap */
# define BUG_HEADERS	 (0x00000020) /* debug bitmap */
# define BUG_CONNECT	 (0x00000040) /* debug bitmap */
# define BUG_HELO	 (0x00000080) /* debug bitmap */
# define BUG_MAILFROM	 (0x00000100) /* debug bitmap */
# define BUG_RCPTTO	 (0x00000200) /* debug bitmap */
# define BUG_HEADER	 (0x00000400) /* debug bitmap */
# define BUG_EOM	 (0x00000800) /* debug bitmap */
# define BUG_EOH	 (0x00001000) /* debug bitmap */
# define BUG_CLOSE	 (0x00002000) /* debug bitmap */
# define BUG_ABORT	 (0x00004000) /* debug bitmap */
# define BUG_EDIT	 (0x00008000) /* debug bitmap */
# define BUG_ADD	 (0x00010000) /* debug bitmap */
# define BUG_RBL	 (0x00020000) /* debug bitmap */
# define BUG_DELETE	 (0x00040000) /* debug bitmap */


/********************************************************
** The various modes of this program.
*/
# define MODE_RUN_AS_MILTER	(0)
# define MODE_DUMP_DATABASE	(1)
# define MODE_ADD_BY_HAND	(2)
# define MODE_GARBAGE_COLLECT	(3)
# define MODE_BOOTSTRAP		(4)

/********************************************************
** Defaults that can be reset with -D when compiling.
*/
EXTERN char *ListenPort;
# ifndef LISTENPORT
#	define LISTENPORT "inet:99@localhost"    /* how to listen */
# endif

EXTERN char *PrimaryDatabaseLoc;
EXTERN DB *Dp1;		/* The primary database */
# ifndef PRIMARYDBFILE
#	define PRIMARYDBFILE "/etc/mail/milter/slow/ip.db"
# endif
EXTERN char *SecondaryDatabaseLoc;
EXTERN DB *Dp2;		/* The secondary database */
# ifndef SECONDARYDBFILE
#	define SECONDARYDBFILE "/etc/mail/milter/slow/events.db"
# endif

# ifndef CFFILE
#	define CFFILE "/etc/mail/milter/slow/slow.conf" /* configuration file */
# endif

/********************************************************
** Defaults that can be overridden in the
** configuration file.
*/

EXTERN char *XTrackHeader;
#define X_TRACK_HEADER NULL

EXTERN bool LookBackOne;
EXTERN bool AllowWhiteListIPs;

EXTERN int MaxHeaderRcpts;
# define MAX_HEADER_RCPTS			(200)
# define BIT_TOO_MANY_HDR_RCPTS	(0x00000001) /* database bitmap */

EXTERN int MaxRcptsPerEnvelope;
# define MAX_RCPTS_PER_ENV			(200)
# define BIT_TOO_MANY_ENV_RCPTS	(0x00000002) /* database bitmap */

EXTERN char **HoneyHosts;
EXTERN char *HoneyFile;
# define BIT_GOT_HONEYPOT  	(0x00000004) /* database bitmap */

EXTERN bool CheckMessageId;
# define BIT_BAD_MSG_ID		(0x00000008) /* database bitmap */

EXTERN bool CheckFromHeader;
# define BIT_BAD_FROM_HEAD	(0x00000010) /* database bitmap */

EXTERN bool CheckSenderHost;
# define BIT_BAD_HOST		(0x00000020) /* database bitmap */

EXTERN char **RBLList;
# define DEFAULT_RBL_LIST 	NULL
# define BIT_RBL_BAD		(0x00000040) /* database bitmap */

EXTERN bool MilterAbort;
# define BIT_MILTER_ABORTED	(0x00000080) /* database bitmap */

EXTERN bool AdvanceWrite;
# define BIT_ADVANCEWRITE	(0x00000100) /* database bitmap */

EXTERN bool CheckForged;
# define BIT_FORGED		(0x00000200) /* database bitmap */

# define BIT_FROMMX		(0x00000400) /* database bitmap */
# define BIT_NOTINET		(0x00000800) /* database bitmap */

/********************************************************
** Global variables set by main() and read-only by
** all the threads.
*/
EXTERN char *Prog;	/* Basename of the milter invocation */

/********************************************************
** Pattern for the context specific data
*/
typedef struct priv {
	PRIMARY_DATUM	 ip;		/* IPv4 number in binary */
	char   		*iptxt;		/* IPv4 number in human readable text */
	BITMAP		 bits;		/* Bit map of binary events */
	int		 envrcpts;	/* Number good recipients */
	int		 badrcpts; 	/* Number bad recipients */
	int		 honeyrcpts; 	/* Number honeypot recipients */
	int		 nhdrrcpts;	/* Number of header recipients */
	char	       **hdrrcpts;	/* List of header recipients */
	char		*midstr;	/* Found a Message-ID header */
} PRIV;

/*********************************************
** Misc. sizes and limits.
*/
# define MAX_FAILS_M (5) /* how many times should malloc() fail? */

/*
** Information used by the "slowedit find" command.
*/
# define SLOWLOGICNONE     0
# define SLOWLOGICEQUAL    1
# define SLOWLOGICGREATER  2
# define SLOWLOGICLESSTHAN 3

# define SLOWBLOGICAND     0
# define SLOWBLOGICOR      1

typedef struct {
	int relation;
	int value;
} LOGICITEM;

typedef struct {
# define SLOWSETBITS       (0)	/* set by foo=set   */
# define SLOWONLYBITS      (1)	/* set by foo=only  */
# define SLOWCLEARBITS     (2)	/* set by foo=clear */
	BITMAP bits[4];
	int    andor;		/* logical AND or OR of the above */
	LOGICITEM envrcpts;
	LOGICITEM hdrrcpts;
	LOGICITEM honeyrcpts;
	LOGICITEM bad;
# if HAVE_REGEX_H && HAVE_REGCOMP
	regex_t *reg;
# else
	char *reg;
# endif
} LOGICSTRUCT;
/*********************************************
** Function prototypes
*/

/* in main.c */
sfsistat  push_to_db(SMFICTX *, PRIV *, int);


/* in readconf.c */
void setdefaults(void);		/* in readconf.c */
void readconf(char *, char *);	/* in readconf.c */

/* in util.c */
void milterr(char *, char *, int, int, int, char *, char *);
char **push_list(char *, char **, int);
char **free_list(char **);
char **mkargv(char *, int, int);
void print_list(char *, char **, FILE *);
bool is_in_list(char *, char **);
void read_honey(void);
void set_debug(char *);
char *cleanup(char *string);
void *try_alloc(char *, int, size_t, int);
void *try_strdup(char *, int, char *, int);
void *try_realloc(char *, int, void *, size_t, int);
unsigned long revbytes(unsigned long);
time_t parse_date(char *);


/* in database.c */
void init_database_mutex(void);
DB *open_database(char *, int);
void close_database(DB *);
int put_ip_database(DB *, PRIMARY_KEY, PRIMARY_DATUM, bool, int);
int del_ip_database(DB *, DB *, PRIMARY_KEY, time_t, int);
int get_db_version(DB *, int);
PRIMARY_DATUM *get_ip_database(DB *, PRIMARY_KEY, int *, int);
int put_event_database(DB *, SECONDARY_KEY *, SECONDARY_DATUM *);
int del_event_database(DB *, SECONDARY_KEY *);
SECONDARY_DATUM *get_event_database(DB *, SECONDARY_KEY *, bool);
int dump_database(DB *, DB *, FILE *);
char *event_to_str(char *, time_t, SECONDARY_DATUM *, int);


/* in mx.c */
char **getmx(char *, char **);
int    rbl_lookup(char *, char *, int);

/* in header.c */
char **header_recipient(char **, char *);
char *deRFC822(char *);
PRIMARY_KEY header_received(char *);
bool header_messageid(char *);

/* regression testing in test.c */
void test_init(int);
void test_connect(char *);
void test_helo(char *);
void test_mailfrom(char *);
void test_rcptto(char *);
void test_header(char *);
void test_eoh(char *);
void test_eom(char *);
void test_close(char *);
void test_abort(char *);
void test_db(char *);
void test_add(char *);
void test_delete(char *);
void test_rbl(char *);

/* in edit.c */
bool slowedit(int, int, char **);
bool slowadd(char *,int, int, char **);
bool slowlist(char *,int, int, char **);
bool slowfind(char *,int, int, char **);
bool slowdelete(char *,int, int, char **);
bool slowalias(char *,int, int, char **);
bool slowwhite(char *,int, int, char **);
bool slowtrim(char *,int, int, char **);
bool is_envent(char *);
bool slowsetpriv(char *,char *);
LOGICSTRUCT *slowlogicparse(char *);
void show_events(char *);

/* in compat.c */
# ifndef HAVE_BASENAME
	char *basename(char *);
# endif
# ifndef HAVE_CUSERID
	char *cuserid(char *);
# endif
# ifndef HAVE_MEMSET
#	define memset(a,b,c) bzero(a,c)
# endif
# ifndef HAVE_MEMCPY
#	define memcpy(a,b,c) bcopy(b,a,c)
# endif
# ifndef HAVE_STRERROR
	char *strerror(int);
# endif
# ifndef HAVE_STRCHR
	char *strchr(char *, int);
# endif
# ifndef HAVE_STRRCHR
	char *strrchr(char *, int);
# endif
# Change User Description Committed
#7 4222 bryan_costales Massive rewrite to speed up the database writes.
Using a single database now with duplicate keys
where the keys are the IP numbers. Added a purge
command and removed the garbage command. Fixed
some leaking memory bugs and properly closed the
database in a few places were it was not
properly closed. Updated the docs to reflect
this and bumped both the database version and
release number. Running on a FreeBSD 3.x machine
and a Solaris 9 machine.
#6 4052 bryan_costales Implimented:
    whitelisting
    AddMXHost for MX servers that lie
    Converted to thread safe DNS routines
    garbage collection
    RunAsUser and RunAsGroup for root startups
    rebuild the database
    summarize by IP number
Finished all documentation.
Moved release from alpha to beta
#5 4030 bryan_costales Finished documenting the configuration file
Fixed a race condition and a core dump bug.
Added hooks for whitelisting and IP aliasing
Added support for Berkeley DB 4.2
Converted to htonl() and ntohl()

Known Bugs:
    ip.db cannot be shared over NFS
    IP tracking from MX hosts can fail
    A RunAsUser config option is needed.
#4 3998 bryan_costales Brought the whole distribution up to V0.9
Added a huge abount of documentation.
Added slowedit find
Created startup scripts to launch for testing
Fixed numerous bugs.
Fixed a few portablity issues.
Installed hooks for whitelisting and IP aliases.
#3 3957 bryan_costales Added rbl lookup support and testing for same.
Folded in support for smfi_stop().
Added lots of slowedit commands
Fixed a serious bug in MX lookups.
Added to documentation.
#2 3890 bryan_costales This is the 0.6 release. The following have been
added with the uses indicated:

    Source files: edit.c -- the slowedit functions
              compat.c -- missing system files
    Autoconf:     configure.ac, makefile.am config.h
              aclocal.m4 acinclude.m4 build/
    Documents:    doc/ -- html and man(1) documents
    Testing:      tests/ -- regressive testing
    TODO:          -- revised to show actual progress
#1 3838 bryan_costales This is pre-release 0.5 (rcs numbering) which includes:
    The milter source files and Makefile
    A regressive testing subdirectory with Makefile and /bin/sh scripts.
    A patches subdirectory with a patch file for V8.13 sendmail
All have been compiled and tested on a 64bit Sun Solaris 9 machine.