I often want to query a specific key instead of dumping out the entire database. This lets you do things like:
$ spamdb 180.124.41.143 TRAPPED|180.124.41.143|1508373987 or: $ spamdb 74.125.198.26 180.124.41.143 107.161.26.205 WHITE|74.125.198.26|||1506223558|1506223558|1509333958|1|0 TRAPPED|180.124.41.143|1508373987 No error is displayed for missing addresses but the exit value will be 1 instead of 0 in this case. - todd Index: usr.sbin/spamdb/spamdb.8 =================================================================== RCS file: /cvs/src/usr.sbin/spamdb/spamdb.8,v retrieving revision 1.19 diff -u -p -u -r1.19 spamdb.8 --- usr.sbin/spamdb/spamdb.8 11 Oct 2017 18:25:07 -0000 1.19 +++ usr.sbin/spamdb/spamdb.8 18 Oct 2017 16:17:41 -0000 @@ -22,10 +22,8 @@ .Nd spamd database tool .Sh SYNOPSIS .Nm spamdb -.Oo Oo Fl Tt Oc -.Fl a Ar keys Oc -.Oo Oo Fl GTt Oc -.Fl d Ar keys Oc +.Op Fl adGTt +.Op Ar keys ... .Sh DESCRIPTION .Nm manipulates the spamd database in @@ -35,7 +33,7 @@ used for .Pp The options are as follows: .Bl -tag -width Ds -.It Fl a Ar keys +.It Fl a Add or update the entries for .Ar keys . This can be used to whitelist one or more IP addresses @@ -46,7 +44,7 @@ If any specified match entries already in the spamd database, .Nm updates the entry's time last seen to now. -.It Fl d Ar keys +.It Fl d Delete entries for .Ar keys . .It Fl G @@ -90,9 +88,12 @@ Otherwise .Ar keys must be numerical IP addresses. .Ss DATABASE OUTPUT FORMAT -If invoked without any arguments, +If invoked without any options, .Nm lists the contents of the database in a text format. +If one or more +.Ar keys +are specified, only matching entries will be printed. .Pp For SPAMTRAP entries the format is: .Pp Index: usr.sbin/spamdb/spamdb.c =================================================================== RCS file: /cvs/src/usr.sbin/spamdb/spamdb.c,v retrieving revision 1.33 diff -u -p -u -r1.33 spamdb.c --- usr.sbin/spamdb/spamdb.c 12 Oct 2017 09:28:56 -0000 1.33 +++ usr.sbin/spamdb/spamdb.c 18 Oct 2017 16:21:21 -0000 @@ -186,10 +186,81 @@ dbupdate(DB *db, char *ip, int add, int } int +print_entry(DBT *dbk, DBT *dbd) +{ + struct gdata gd; + char *a, *cp; + + if ((dbk->size < 1) || gdcopyin(dbd, &gd) == -1) { + warnx("bogus size db entry - bad db file?"); + return (1); + } + a = malloc(dbk->size + 1); + if (a == NULL) + err(1, "malloc"); + memcpy(a, dbk->data, dbk->size); + a[dbk->size]='\0'; + cp = strchr(a, '\n'); + if (cp == NULL) { + /* this is a non-greylist entry */ + switch (gd.pcount) { + case -1: /* spamtrap hit, with expiry time */ + printf("TRAPPED|%s|%lld\n", a, + (long long)gd.expire); + break; + case -2: /* spamtrap address */ + printf("SPAMTRAP|%s\n", a); + break; + default: /* whitelist */ + printf("WHITE|%s|||%lld|%lld|%lld|%d|%d\n", a, + (long long)gd.first, (long long)gd.pass, + (long long)gd.expire, gd.bcount, + gd.pcount); + break; + } + } else { + char *helo, *from, *to; + + /* greylist entry */ + *cp = '\0'; + helo = cp + 1; + from = strchr(helo, '\n'); + if (from == NULL) { + warnx("No from part in grey key %s", a); + free(a); + return (1); + } + *from = '\0'; + from++; + to = strchr(from, '\n'); + if (to == NULL) { + /* probably old format - print it the + * with an empty HELO field instead + * of erroring out. + */ + printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n", + a, "", helo, from, (long long)gd.first, + (long long)gd.pass, (long long)gd.expire, + gd.bcount, gd.pcount); + + } else { + *to = '\0'; + to++; + printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n", + a, helo, from, to, (long long)gd.first, + (long long)gd.pass, (long long)gd.expire, + gd.bcount, gd.pcount); + } + } + free(a); + + return (0); +} + +int dblist(DB *db) { DBT dbk, dbd; - struct gdata gd; int r; /* walk db, list in text format */ @@ -197,80 +268,52 @@ dblist(DB *db) memset(&dbd, 0, sizeof(dbd)); for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r; r = db->seq(db, &dbk, &dbd, R_NEXT)) { - char *a, *cp; - - if ((dbk.size < 1) || gdcopyin(&dbd, &gd) == -1) { - db->close(db); - errx(1, "bogus size db entry - bad db file?"); - } - a = malloc(dbk.size + 1); - if (a == NULL) - err(1, "malloc"); - memcpy(a, dbk.data, dbk.size); - a[dbk.size]='\0'; - cp = strchr(a, '\n'); - if (cp == NULL) { - /* this is a non-greylist entry */ - switch (gd.pcount) { - case -1: /* spamtrap hit, with expiry time */ - printf("TRAPPED|%s|%lld\n", a, - (long long)gd.expire); - break; - case -2: /* spamtrap address */ - printf("SPAMTRAP|%s\n", a); - break; - default: /* whitelist */ - printf("WHITE|%s|||%lld|%lld|%lld|%d|%d\n", a, - (long long)gd.first, (long long)gd.pass, - (long long)gd.expire, gd.bcount, - gd.pcount); - break; - } - } else { - char *helo, *from, *to; - - /* greylist entry */ - *cp = '\0'; - helo = cp + 1; - from = strchr(helo, '\n'); - if (from == NULL) { - warnx("No from part in grey key %s", a); - free(a); - goto bad; - } - *from = '\0'; - from++; - to = strchr(from, '\n'); - if (to == NULL) { - /* probably old format - print it the - * with an empty HELO field instead - * of erroring out. - */ - printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n", - a, "", helo, from, (long long)gd.first, - (long long)gd.pass, (long long)gd.expire, - gd.bcount, gd.pcount); - - } else { - *to = '\0'; - to++; - printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n", - a, helo, from, to, (long long)gd.first, - (long long)gd.pass, (long long)gd.expire, - gd.bcount, gd.pcount); - } + if (print_entry(&dbk, &dbd) != 0) { + r = -1; + break; } - free(a); } db->close(db); db = NULL; - return (0); - bad: + return (r == -1); +} + +int +dbshow(DB *db, char **addrs) +{ + DBT dbk, dbd; + int errors = 0; + char *a; + + /* look up each addr */ + while ((a = *addrs) != NULL) { + memset(&dbk, 0, sizeof(dbk)); + dbk.size = strlen(a); + dbk.data = a; + memset(&dbd, 0, sizeof(dbd)); + switch (db->get(db, &dbk, &dbd, 0)) { + case -1: + warn("db->get failed"); + errors++; + goto done; + case 0: + if (print_entry(&dbk, &dbd) != 0) { + errors++; + goto done; + } + break; + case 1: + default: + /* not found */ + errors++; + break; + } + addrs++; + } + done: db->close(db); db = NULL; - errx(1, "incorrect db format entry"); - /* NOTREACHED */ - return (1); + return (errors); } extern char *__progname; @@ -278,7 +321,7 @@ extern char *__progname; static int usage(void) { - fprintf(stderr, "usage: %s [[-Tt] -a keys] [[-GTt] -d keys]\n", __progname); + fprintf(stderr, "usage: %s [-adGTt] [keys ...]\n", __progname); exit(1); /* NOTREACHED */ } @@ -335,7 +378,10 @@ main(int argc, char **argv) switch (action) { case 0: - return dblist(db); + if (argc) + return dbshow(db, argv); + else + return dblist(db); case 1: if (type == GREY) errx(2, "cannot add GREY entries");