/************************************************************ ** $Id: database.c,v 0.8 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. ** ** Entry points defined in this file: ** ** open_database(): ** Open a database, creating it if asked to. ** close_database(): ** Close a database. ** put_event_database(): ** Add an ip/date item to the secondary database. ** get_event_database(): ** Read an ip/date item from the secondary database. ** dump_events(): ** Print the database contents to a file pointer. ** event_to_str(): ** Format the event for printing or logging. *************************************************************/ # define EXTERN extern # include "slow.h" DB * open_database(char *fname, int force) { static DB *dp; u_int32_t flags = DB_THREAD|DB_DIRTY_READ; int ret; ret = db_create(&dp, (DB_ENV *)NULL, 0); if (ret != 0) { milterr(Prog, __FILE__, __LINE__, FALSE, errno, fname, "db_create database"); } ret = dp->set_flags(dp, DB_DUP); if (ret != 0) { milterr(Prog, __FILE__, __LINE__, FALSE, errno, fname, "db_set_flags database"); } if (force == TRUE) flags |= DB_CREATE; if (force == DBREADONLY) flags |= DB_RDONLY; ret = dp->open(dp, NULL, fname, NULL, DB_HASH, flags, 0644); if (ret != 0) { milterr(Prog, __FILE__, __LINE__, FALSE, errno, fname, "db_open database"); } return dp; } void close_database(DB *dp) { (void)dp->close(dp, 0); } int get_db_version(DB *dp, int threading) { SECONDARY_DATUM *rp; int ret; rp = get_event_database(dp, NULL, FALSE, &ret); if (rp == NULL) return 0; (void) free(rp); if (ret != 0) return 0; return DATABASE_VERSION; } int put_event_database(DB *dp, PRIMARY_KEY ip, SECONDARY_DATUM *event) { DBT key, data; int ret; extern int errno; if (dp == NULL) return EFAULT; (void) memset(&data, 0, sizeof data); (void) memset(&key, 0, sizeof key); key.data = &ip; key.size = sizeof(PRIMARY_KEY); data.data = event; data.size = sizeof(SECONDARY_DATUM); ret = dp->put(dp, NULL, &key, &data, 0); if (ret != 0) { return ret; } (void)dp->sync(dp, 0); return 0; } int del_event_database(DB *dp, PRIMARY_KEY *ip, time_t t) { DBT key, data; int ret; DBC *curs; extern int errno; if (dp == NULL) return EFAULT; (void) memset(&data, 0, sizeof data); (void) memset(&key, 0, sizeof key); key.data = ip; key.size = sizeof(PRIMARY_KEY); if (t == 0) { ret = dp->del(dp, NULL, &key, 0); if (ret != 0) return ret; (void)dp->sync(dp, 0); return 0; } (void) memset(&data, 0, sizeof data); data.flags = DB_DBT_REALLOC; ret = dp->get(dp, NULL, &key, &data, 0); if (ret != 0) return ret; ret = Dp->cursor(Dp, NULL, &curs, 0); if (ret != 0) return ret; (void) memset(&data, 0, sizeof data); (void) memset(&key, 0, sizeof key); key.flags = DB_DBT_REALLOC; data.flags = DB_DBT_REALLOC; for(;;) { ret = curs->c_get(curs, &key, &data, DB_NEXT); if (ret == DB_NOTFOUND) break; if (ret != 0) return ret; if (*((PRIMARY_KEY *)key.data) != *ip) continue; if (((SECONDARY_DATUM *)data.data)->date != t) continue; ret = curs->c_del(curs, 0); if (ret != 0) return ret; } (void) curs->c_close(curs); (void)dp->sync(dp, 0); return 0; } SECONDARY_DATUM * get_event_database(DB *dp, PRIMARY_KEY *ip, bool verbose, int *ret) { DBT key, data; extern int errno; PRIMARY_KEY p; if (dp == NULL) return NULL; (void) memset(&key, 0, sizeof key); (void) memset(&data, 0, sizeof data); /* ** If the datum to look up is NULL, look up the version. */ if (ip == NULL) { p = DATABASE_VERSION; key.data = &p; } else key.data = ip; key.size = sizeof(PRIMARY_KEY); data.data = NULL; data.size = 0; data.ulen = 0; data.flags = DB_DBT_MALLOC; *ret = 0; *ret = dp->get(dp, NULL, &key, &data, 0); if (*ret != 0) { if (verbose) { dp->err(dp, *ret, "%s", DatabaseLoc); } return NULL; } return (SECONDARY_DATUM *)(data.data); } /* ** Walk the databases, producing a report of its contents. ** The fp pointer is where to print the report, and is usually ** the standard output. ** ** This routine is intended for use from the command-line, and is ** not thread safe. */ int dump_events(DB *recdp, FILE *fp, int clean, PRIMARY_KEY ip) { DBT key, data; int ret; DBC *curs; SECONDARY_DATUM *event; PRIMARY_KEY *p; struct in_addr in; char ipbuf[MAXHOSTNAMELEN]; extern int errno; if (recdp == NULL) return 0; ret = recdp->cursor(recdp, NULL, &curs, 0); if (ret != 0) { return ret; } (void) memset(&data, 0, sizeof data); (void) memset(&key, 0, sizeof key); key.flags = DB_DBT_REALLOC; data.flags = DB_DBT_REALLOC; for (;;) { ret = curs->c_get(curs, &key, &data, DB_NEXT); if (ret == DB_NOTFOUND) break; if (ret != 0) { (void) curs->c_close(curs); return ret; } if (key.data == NULL) continue; /* * Always silently skip the version. */ event = data.data; p = key.data; if (*p == DATABASE_VERSION) continue; if (ip != 0 && *p != ip) continue; (void) memcpy(&in.s_addr, (char *)p, sizeof(in.s_addr)); (void) sprintf(ipbuf, "%s", inet_ntoa(in)); fprintf(fp, "%s\n", event_to_str(ipbuf, event->date, event, FALSE)); } (void) curs->c_close(curs); return 0; } /* ALIAS */ char * alias_to_str(char *ipbuf, char *alias, int threading) { char buf[BUFSIZ]; if (ipbuf == NULL || alias == NULL) return NULL; (void) sprintf(buf, "%s aliased to %s", ipbuf, alias); return try_strdup(__FILE__, __LINE__, buf, threading); } char * event_to_str(char *ipbuf, time_t date, SECONDARY_DATUM *event, int threading) { char buf[BUFSIZ]; struct tm *t; if (ipbuf == NULL) return NULL; if (date == TYPE_RECORD_WHITELIST) { (void) sprintf(buf, "%s: Whitelisted", ipbuf); return try_strdup(__FILE__, __LINE__, buf, threading); } t = localtime(&date); (void) sprintf(buf, "%s: %02d/%02d/%d.%02d:%02d:%02d ", ipbuf, t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec); if (event == NULL) { if (errno != 0) { (void) sprintf(buf+strlen(buf), "%s", errno == DB_NOTFOUND ? "Item not in database (need to garbage collect)" : "Lookup error while processing item"); } else { (void) sprintf(buf+strlen(buf), "Garbage Collected"); } return try_strdup(__FILE__, __LINE__, buf, threading); } (void) sprintf(buf+strlen(buf), "er=%d,", event->envrcpts); (void) sprintf(buf+strlen(buf), "hr=%d,", event->headrcpts); (void) sprintf(buf+strlen(buf), "ho=%d,", event->honeyrcpts); (void) sprintf(buf+strlen(buf), "br=%d,", event->badrcpts); if (event->eventmap != 0) { if (isbitset(event->eventmap, BIT_TOO_MANY_HDR_RCPTS)) (void) strcat(buf, "hed,"); if (isbitset(event->eventmap, BIT_TOO_MANY_ENV_RCPTS)) (void) strcat(buf, "env,"); if (isbitset(event->eventmap, BIT_GOT_HONEYPOT)) (void) strcat(buf, "hon,"); if (isbitset(event->eventmap, BIT_BAD_MSG_ID)) (void) strcat(buf, "mid,"); if (isbitset(event->eventmap, BIT_BAD_FROM_HEAD)) (void) strcat(buf, "frm,"); if (isbitset(event->eventmap, BIT_BAD_HOST)) (void) strcat(buf, "bho,"); if (isbitset(event->eventmap, BIT_RBL_BAD)) (void) strcat(buf, "rbl,"); if (isbitset(event->eventmap, BIT_MILTER_ABORTED)) (void) strcat(buf, "abo,"); if (isbitset(event->eventmap, BIT_ADVANCEWRITE)) (void) strcat(buf, "pip,"); if (isbitset(event->eventmap, BIT_FORGED)) (void) strcat(buf, "for,"); if (isbitset(event->eventmap, BIT_FROMMX)) (void) strcat(buf, "mmx,"); if (isbitset(event->eventmap, BIT_NOTINET)) (void) strcat(buf, "net,"); if (isbitset(event->eventmap, BIT_ADDEDIP)) (void) strcat(buf, "aip,"); } (void) sprintf(buf+strlen(buf), "msgid=%s", event->msgid); return try_strdup(__FILE__, __LINE__, buf, threading); }
# | 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. |