I have an OK on the man page bits. Anyone else want to chime in?
- todd
On Wed, 18 Oct 2017 10:22:00 -0600, "Todd C. Miller" wrote:
> 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", __progn
> ame);
> + 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");
>