/************************************************************ ** $Id: test.c,v 0.7 2003/12/29 16:45:38 bcx Exp bcx $ ** ** Copyright Bryan Costales and Perforce Software, Inc. 2003 ** ** This code is "open source" as defined by version 1.9 of ** the Open Source Definition from: ** ** http://www.opensource.org/docs/definition.php. ** ** Tests run in this file can only be done before ** any threads are launched (i.e. from the main() routine). ** See the scripts in the tests directory for more details. ** *************************************************************/ # define EXTERN extern # include "slow.h" /* * The following needed to be copied from milter.h in the * sendmail source for the routines in this file to work. */ # define MAX_MACROS_ENTRIES 4 PRIV *Priv = NULL; struct smfi_str { unsigned int ctx_id; /* thread id */ unsigned int ctx_sd; /* socket descriptor */ int ctx_dbg; /* debug level */ time_t ctx_timeout; /* timeout */ int ctx_state; /* state */ smfiDesc_ptr ctx_smfi; /* filter description */ unsigned long ctx_pflags; /* protocol flags */ char **ctx_mac_ptr[MAX_MACROS_ENTRIES]; char *ctx_mac_buf[MAX_MACROS_ENTRIES]; char *ctx_reply; /* reply code */ void *ctx_privdata; /* private data */ } Ctx; void test_init(int setpriv) { (void) memset(&Ctx, '\0', sizeof(SMFICTX)); Ctx.ctx_id = 1; if (setpriv == TRUE) { Priv = malloc(sizeof(PRIV)); (void) memset(Priv, '\0', sizeof(PRIV)); Ctx.ctx_privdata = Priv; } } /* ** These various test routines all get a string for testing. ** These are all passed using the -X command-line switch. ** Multilple arguments must be separated by commas, e.g. -X"a,b" ** All exit() after the individual test. */ void test_connect(char *string) { union { _SOCK_ADDR in; struct sockaddr_in sin; } n; unsigned long ip; char *host; char **argv; char buf[BUFSIZ]; extern sfsistat xxfi_connect(SMFICTX *, char *, _SOCK_ADDR *); if (string == NULL) { (void) printf("Usage: -Dconnect -X \"hostname,ipaddr\"\n"); exit(0); } argv = mkargv(string, ',', FALSE); if (argv[0] == NULL || argv[1] == NULL) { (void) printf("Usage: -Dconnect -X \"hostname,ipaddr\"\n"); exit(0); } if (((int)(ip = inet_network(argv[1]))) == -1) { (void) fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); exit(0); } test_init(FALSE); LookBackOne = TRUE; /* * First test with no macros defined and no AF_INET. * Should get flags=[NET] */ n.in.sa_family = 0; (void) memcpy( &n.sin.sin_addr, &ip, sizeof(PRIMARY_DATUM)); host = strdup(argv[0]); (void) xxfi_connect(&Ctx, host, &n.in); /* * Second test with no macros defined and AF_INET defined. * Should get empty flags= */ n.in.sa_family = AF_INET; (void) memcpy( &n.sin.sin_addr, &ip, sizeof(PRIMARY_DATUM)); host = strdup(argv[0]); (void) xxfi_connect(&Ctx, host, &n.in); /* * Then test the ${client_resolve} macro. * Should get flags=[FOR] */ (void) sprintf(buf, "{client_resolve}, forged"); Ctx.ctx_mac_ptr[0] = mkargv(buf, ',', FALSE); Ctx.ctx_mac_buf[0] = buf; n.in.sa_family = AF_INET; (void) memcpy( &n.sin.sin_addr, &ip, sizeof(PRIMARY_DATUM)); host = strdup(argv[0]); (void) xxfi_connect(&Ctx, host, &n.in); Ctx.ctx_mac_ptr[0] = NULL; Ctx.ctx_mac_buf[0] = NULL; /* * Add the hostname to the list of MX hosts and * try again. * Should get <nil> for IP number, and flags=[MMX] */ MxHosts = push_list(argv[0], MxHosts, FALSE); n.in.sa_family = AF_INET; (void) memcpy( &n.sin.sin_addr, &ip, sizeof(PRIMARY_DATUM)); host = strdup(argv[0]); (void) xxfi_connect(&Ctx, host, &n.in); exit(0); } void test_helo(char *string) { char buf[BUFSIZ]; extern sfsistat xxfi_helo(SMFICTX *, char *); test_init(TRUE); /* * Test the ${illegalpipe} macro. * Should get flags=[PIP] */ AdvanceWrite = TRUE; (void) sprintf(buf, "{illegalpipe}, true"); Ctx.ctx_mac_ptr[0] = mkargv(buf, ',', FALSE); Ctx.ctx_mac_buf[0] = buf; (void) xxfi_helo( &Ctx, string); Ctx.ctx_mac_ptr[0] = NULL; Ctx.ctx_mac_buf[0] = NULL; exit(0); } void test_mailfrom(char *string) { char **argv; extern sfsistat xxfi_envfrom(SMFICTX *, char **); if (string == NULL) { (void) printf("Usage: -Dmailfrom -X \"sender@domain\"\n"); exit(0); } test_init(TRUE); CheckSenderHost = TRUE; /* * Test the envelope recipient's host. * Should get flags=[FRM] for a bad host name. */ argv = mkargv(string, ',', FALSE); (void) xxfi_envfrom( &Ctx, argv); exit(0); } void test_rcptto(char *string) { char **argv; char *addr; extern sfsistat xxfi_envto(SMFICTX *, char **); if (string == NULL) { (void) printf("Usage: -Drcptto -X \"recipient@domain\"\n"); exit(0); } test_init(TRUE); CheckFromHeader = TRUE; /* * Should get flags=[HON] for a honey addr */ addr = strdup("bob@x.y.z.0.1.2.com"); HoneyHosts = mkargv(addr, ',', FALSE); (void) xxfi_envto(&Ctx, HoneyHosts); /* * Test the envelope recipient's host. * Three times to get the count to 3. */ argv = mkargv(string, ',', FALSE); (void) xxfi_envto(&Ctx, argv); (void) xxfi_envto(&Ctx, argv); (void) xxfi_envto(&Ctx, argv); exit(0); } /* * Note that the .foo domain prevents these names from * being found in the actual MX list. */ static char *Received = "from spamhost.foo (bay2-f58.bay2.somehost.gov [65.54.247.58])\n\tby ourmx.foo (8.13.1/8.13.1) with ESMTP id h9VJ49rM005383\n\tfor <user@ourhost.foo>; Fri, 31 Oct 2003 11:04:09 -0800 (PST)"; void test_header(char *string) { char *addr; char *received; extern sfsistat xxfi_header(SMFICTX *, char *, char *); /* string is ignored */ test_init(TRUE); /* * Does it recognize the XTrackHeader? */ XTrackHeader = strdup("X-test-x-track"); (void) xxfi_header(&Ctx, XTrackHeader, "testing"); /* * A Received: header not from one of our * MX servers, then one from one of our MX servers. */ LookBackOne = TRUE; Priv->ip = 0; received = strdup(Received); (void) xxfi_header(&Ctx, "Received", received); addr = strdup("ourmx.foo"); MxHosts = push_list(addr, MxHosts, FALSE); received = strdup(Received); (void) xxfi_header(&Ctx, "Received", received); Priv->hdrrcpts = NULL; /* * A dozen vairations on recipient headers. */ Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("(John Doe) doe@ourhost.gov"); (void) xxfi_header(&Ctx, "Cc", addr); Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("\"John Doe\" <doe@ourhost.gov>"); (void) xxfi_header(&Ctx, "Cc", addr); Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("doe"); (void) xxfi_header(&Ctx, "Bcc", addr); Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("doe@ourhost.gov (John Doe)"); (void) xxfi_header(&Ctx, "Cc", addr); Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("<<<doe@ourhost.gov>>>"); (void) xxfi_header(&Ctx, "Bcc", addr); Priv->hdrrcpts = free_list(Priv->hdrrcpts); addr = strdup("andy@ourhost.gov, <bob@ourhost.gov>, (Carl) carl@ourhost.gov"); (void) xxfi_header(&Ctx, "To", addr); /* * Next check the Message-ID header. */ addr = strdup("<a@b>"); (void) xxfi_header(&Ctx, "Message-Id", addr); addr = strdup("<ab>"); (void) xxfi_header(&Ctx, "Message-Id", addr); addr = strdup("<@b>"); (void) xxfi_header(&Ctx, "Message-Id", addr); addr = strdup("<a@>"); (void) xxfi_header(&Ctx, "Message-Id", addr); addr = strdup("a@b"); (void) xxfi_header(&Ctx, "Message-Id", addr); /* * Lastly check the From: header. */ CheckFromHeader = TRUE; addr = strdup("a"); (void) xxfi_header(&Ctx, "From", addr); addr = strdup("a@"); (void) xxfi_header(&Ctx, "From", addr); addr = strdup("a@host.foo"); (void) xxfi_header(&Ctx, "From", addr); exit(0); } void test_eoh(char *string) { char buf[BUFSIZ]; int i; extern sfsistat xxfi_eoh(SMFICTX *); /* string is ignored */ test_init(TRUE); CheckMessageId = TRUE; Priv->midstr = NULL; Priv->hdrrcpts = NULL; for (i = 0; i < 6; i++) { (void)sprintf(buf, "%d", i); Priv->hdrrcpts = push_list(buf, Priv->hdrrcpts, FALSE); } (void) xxfi_eoh(&Ctx); exit(0); } void test_close(char *string) { extern sfsistat xxfi_close(SMFICTX *); /* string is ignored */ test_init(TRUE); (void) xxfi_close(&Ctx); (void) printf("close: priv = %x\n", (int)Ctx.ctx_privdata); exit(0); } void test_abort(char *string) { extern sfsistat xxfi_abort(SMFICTX *); /* string is ignored */ test_init(TRUE); (void) xxfi_abort(&Ctx); (void) printf("abort: flags=%s\n", isbitset(BIT_MILTER_ABORTED, Priv->bits)?"[ABO]":""); exit(0); } void test_eom(char *string) { char buf[BUFSIZ]; extern sfsistat xxfi_eom(SMFICTX *); /* string is ignored */ test_init(TRUE); (void) sprintf(buf, "{nbadrcpts}, 6"); Ctx.ctx_mac_ptr[0] = mkargv(buf, ',', FALSE); Ctx.ctx_mac_buf[0] = buf; (void) xxfi_eom(&Ctx); (void) printf("eom: badrcpts=%d\n", Priv->badrcpts); exit(0); } void test_db(char *string) { char **argv; extern sfsistat xxfi_eom(SMFICTX *); char *iptext; if (string == NULL) { (void) printf("Usage: -Ddb -X \"primary.db, secondary.db\"\n"); exit(0); } test_init(TRUE); DoLog = FALSE; LogEvents = FALSE; argv = mkargv(string, ',', FALSE); if (argv[0] == NULL || argv[1] == NULL) { (void) printf("Usage: -Ddb -X \"primary.db, secondary.db\"\n"); exit(0); } /* * Use a path that will fail even if this is tested * by root. */ init_database_mutex(); PrimaryDatabaseLoc = "/foo/bar/foo/bar.db"; errno = 0; Dp1 = open_database(PrimaryDatabaseLoc, TRUE); printf("db: %s: %s\n", PrimaryDatabaseLoc, strerror(errno)); /* * Using the file names specified, first * open with no-force, then open with force. */ PrimaryDatabaseLoc = argv[0]; errno = 0; Dp1 = open_database(PrimaryDatabaseLoc, FALSE); if (Dp1 == NULL) printf("db: %s: %s\n", PrimaryDatabaseLoc, strerror(errno)); else close_database(Dp1); errno = 0; Dp1 = open_database(PrimaryDatabaseLoc, TRUE); if (Dp1 == NULL) { printf("db: %s: %s\n", PrimaryDatabaseLoc, strerror(errno)); exit (0); } else printf("db: %s: successfully opened\n", PrimaryDatabaseLoc); SecondaryDatabaseLoc = argv[1]; errno = 0; Dp2 = open_database(SecondaryDatabaseLoc, TRUE); if (Dp2 == NULL) { printf("db: %s: %s\n", SecondaryDatabaseLoc, strerror(errno)); exit (0); } else printf("db: %s: successfully opened\n", SecondaryDatabaseLoc); /* * Dummy up some records and add them * to the database. */ iptext = try_strdup(__FILE__, __LINE__, "1.2.3.4", FALSE); Priv->iptxt = try_strdup(__FILE__, __LINE__, iptext, FALSE); Priv->ip = inet_network(Priv->iptxt); Priv->bits = (BITMAP) 0; set_bit(BIT_TOO_MANY_HDR_RCPTS, Priv->bits); set_bit(BIT_TOO_MANY_ENV_RCPTS, Priv->bits); set_bit(BIT_GOT_HONEYPOT, Priv->bits); set_bit(BIT_BAD_MSG_ID, Priv->bits); set_bit(BIT_BAD_FROM_HEAD, Priv->bits); set_bit(BIT_BAD_HOST, Priv->bits); set_bit(BIT_RBL_BAD, Priv->bits); set_bit(BIT_MILTER_ABORTED, Priv->bits); set_bit(BIT_ADVANCEWRITE, Priv->bits); set_bit(BIT_FORGED, Priv->bits); set_bit(BIT_FROMMX, Priv->bits); set_bit(BIT_NOTINET, Priv->bits); Priv->envrcpts = 1234; Priv->badrcpts = 1234; Priv->honeyrcpts = 1234; Priv->nhdrrcpts = 1234; Priv->midstr = try_strdup(__FILE__, __LINE__, "<1234@1234.gov>", FALSE); /* * warning: push_to_db clears Priv */ if (push_to_db(&Ctx, Priv, FALSE, 0) != SMFIS_CONTINUE) { printf("%s: %s\n", iptext, strerror(errno)); exit(errno); } else printf("%s: successful write\n", iptext); /* * Now dump what we just wrote. * There should just be one record. */ (void) dump_database(Dp1, Dp2, stdout, FALSE); exit(0); } void test_add(char *string) { char **argv; char *command[3]; char *user; int opt, argc; if (string == NULL) { (void) printf("Usage: -Dadd -X \"primary.db, secondary.db\"\n"); exit(0); } argv = mkargv(string, ',', FALSE); if (argv[0] == NULL || argv[1] == NULL) { (void) printf("Usage: -Dadd -X \"primary.db, secondary.db\"\n"); exit(0); } PrimaryDatabaseLoc = try_strdup(__FILE__, __LINE__, argv[0], FALSE); DoLog = FALSE; LogEvents = FALSE; init_database_mutex(); Dp1 = open_database(PrimaryDatabaseLoc, TRUE); if (Dp1 == NULL) { printf("db: %s: %s\n", PrimaryDatabaseLoc, strerror(errno)); exit (0); } SecondaryDatabaseLoc = try_strdup(__FILE__, __LINE__, argv[1], FALSE); errno = 0; Dp2 = open_database(SecondaryDatabaseLoc, TRUE); if (Dp2 == NULL) { printf("db: %s: %s\n", SecondaryDatabaseLoc, strerror(errno)); exit (0); } command[0] = try_strdup(__FILE__, __LINE__, "1.2.3.4", FALSE); command[1] = try_strdup(__FILE__, __LINE__, "er=1,hr=2,ho=3,br=4,hed,env,hon,mid,frm,bho,rbl,abo,pip,for,mmx,net", FALSE); command[2] = NULL; opt = -1; argc = 2; user = try_strdup(__FILE__, __LINE__, "nobody", FALSE); (void) slowadd(user, opt, argc, command); /* * Now dump what we just wrote. * There should just be one record. */ (void) dump_database(Dp1, Dp2, stdout, FALSE); exit(0); } void test_delete(char *string) { char **argv; char *command[3]; char *user; int opt, argc; if (string == NULL) { (void) printf("Usage: -Ddelete -X \"primary.db, secondary.db\"\n"); exit(0); } argv = mkargv(string, ',', FALSE); if (argv[0] == NULL || argv[1] == NULL) { (void) printf("Usage: -Ddelete -X \"primary.db, secondary.db\"\n"); exit(0); } PrimaryDatabaseLoc = try_strdup(__FILE__, __LINE__, argv[0], FALSE); DoLog = FALSE; LogEvents = FALSE; init_database_mutex(); Dp1 = open_database(PrimaryDatabaseLoc, TRUE); if (Dp1 == NULL) { printf("db: %s: %s\n", PrimaryDatabaseLoc, strerror(errno)); exit (0); } SecondaryDatabaseLoc = try_strdup(__FILE__, __LINE__, argv[1], FALSE); errno = 0; Dp2 = open_database(SecondaryDatabaseLoc, TRUE); if (Dp2 == NULL) { printf("db: %s: %s\n", SecondaryDatabaseLoc, strerror(errno)); exit (0); } command[2] = NULL; opt = -1; argc = 2; user = try_strdup(__FILE__, __LINE__, "nobody", FALSE); command[0] = try_strdup(__FILE__, __LINE__, "1.2.3.1", FALSE); command[1] = try_strdup(__FILE__, __LINE__, "er=1", FALSE); (void) slowadd(user, opt, argc, command); command[0] = try_strdup(__FILE__, __LINE__, "1.2.3.2", FALSE); command[1] = try_strdup(__FILE__, __LINE__, "er=2", FALSE); (void) slowadd(user, opt, argc, command); command[0] = try_strdup(__FILE__, __LINE__, "1.2.3.1", FALSE); command[1] = try_strdup(__FILE__, __LINE__, "02/07/2009:02:46:40", FALSE); (void) slowdelete(user, opt, argc, command); opt = -1; argc = 1; command[0] = try_strdup(__FILE__, __LINE__, "1.2.3.2", FALSE); command[1] = NULL; (void) slowdelete(user, opt, argc, command); exit(0); } void test_rbl(char *string) { char **argv; int r; if (string == NULL) { (void) printf("Usage: -Drbl -X \"rblhost, ipaddress\"\n"); exit(0); } argv = mkargv(string, ',', FALSE); if (argv[0] == NULL || argv[1] == NULL) { (void) printf("Usage: -Drbl -X \"rblhost, ipaddress\"\n"); exit(0); } r = rbl_lookup(argv[0], argv[1], FALSE); if (r != 0) printf("%s: %s %s\n", argv[0], argv[1], r < 0 ? hstrerror(-r) : strerror(r)); else printf("%s: %s rejected\n", argv[0], argv[1]); exit(0); }
# | 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. |