Oh I like this Todd.. nice.
On Fri, Jan 9, 2015 at 9:19 AM, Todd C. Miller
<todd.mil...@courtesan.com> wrote:
> spamd stores the IP addr/mask in a union that can hold either ipv4
> or ipv6. This simplifies the data structures but means that ipv4
> addrs/masks take up 4x as much space as they need to. This can
> be an issue with very large blacklists, like we use on the
> mailing list server. It also means spamd compares addrs regardless
> of the address family.
>
> Adding insult to injury, neither spamd-setup nor the greytrapper
> in spamd support anything other than ipv4. Rather than just
> rip out the unused ipv6 support, I've changed the spamd config
> protocol from:
>
> tag;message;a/m;a/m;a/m...\n
>
> to:
>
> tag;message;af;count;a/m;a/m;a/m...\n
>
> where addr/mask lists are specified on a per-address family basis.
> This lets us store addr/mask pairs in a per-address family list.
> This results in a spamd process that uses almost 1/4 of the old
> one and we never try to match IP addresses of the wrong family.
>
> Before:
> USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
> _spamd 9520 0.0 13.1 1088112 1085244 ?? S Mon01PM 31:50.51 spamd:
> [priv] (greylist) (spamd)
>
> After:
> _spamd 9781 0.0 2.8 236880 232224 ?? S Thu08PM 4:07.29 spamd:
> [priv] (greylist) (spamd)
>
> Comments?
>
> - todd
>
> Index: libexec/spamd/grey.c
> =================================================================== RCS
> file: /cvs/src/libexec/spamd/grey.c,v retrieving revision 1.57 diff
> -u -r1.57 grey.c --- libexec/spamd/grey.c 23 Nov 2014 21:19:47
> -0000 1.57 +++ libexec/spamd/grey.c 9 Jan 2015 13:38:08
> -0000 @@ -58,7 +58,7 @@
> int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *,
> struct sockaddr_in6 *);
>
> -void configure_spamd(char **, size_t, FILE *);
> +void configure_spamd(char **, u_int, FILE *);
> int server_lookup(struct sockaddr *, struct sockaddr *,
> struct sockaddr *);
> int configure_pf(char **, int);
> @@ -76,8 +76,8 @@
> void greyscanner(void);
>
>
> -size_t whitecount, whitealloc;
> -size_t trapcount, trapalloc;
> +u_int whitecount, whitealloc;
> +u_int trapcount, trapalloc;
> char **whitelist;
> char **traplist;
>
> @@ -137,17 +137,18 @@
> * host hits.
> */
> void
> -configure_spamd(char **addrs, size_t count, FILE *sdc)
> +configure_spamd(char **addrs, u_int count, FILE *sdc)
> {
> - size_t i;
> + u_int i;
>
> + /* XXX - doesn't support IPV6 yet */
> fprintf(sdc, "%s;", traplist_name);
> if (count != 0) {
> - fprintf(sdc, "%s;", traplist_msg);
> + fprintf(sdc, "%s;inet;%u", traplist_msg, count);
> for (i = 0; i < count; i++)
> - fprintf(sdc, "%s/32;", addrs[i]);
> + fprintf(sdc, ";%s/32", addrs[i]);
> }
> - fprintf(sdc, "\n");
> + fputc('\n', sdc);
> if (fflush(sdc) == EOF)
> syslog_r(LOG_DEBUG, &sdata, "configure_spamd: fflush failed
> (%m)");
> }
> Index: libexec/spamd/sdl.c
> ===================================================================
> RCS file: /cvs/src/libexec/spamd/sdl.c,v
> retrieving revision 1.20
> diff -u -r1.20 sdl.c
> --- libexec/spamd/sdl.c 8 Jan 2015 22:10:08 -0000 1.20
> +++ libexec/spamd/sdl.c 9 Jan 2015 13:38:08 -0000
> @@ -1,4 +1,4 @@
> -/* $OpenBSD: sdl.c,v 1.20 2015/01/08 22:10:08 millert Exp $ */
> +/* $OpenBSD: sdl.c,v 1.19 2014/10/11 03:25:16 doug Exp $ */
>
> /*
> * Copyright (c) 2003-2007 Bob Beck. All rights reserved.
> @@ -40,20 +40,18 @@
>
> static void sdl_free(struct sdlist *);
> static void sdl_clear(struct sdlist *);
> -int match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b,
> - sa_family_t af);
>
> extern int debug;
> struct sdlist *blacklists = NULL;
> int blc = 0, blu = 0;
>
> int
> -sdl_add(char *sdname, char *sdstring, char ** addrs, int addrc)
> +sdl_add(char *sdname, char *sdstring, char **v4, u_int nv4, char **v6, u_int
> nv6)
> {
> int i, idx = -1;
> char astring[40];
> + char *addr = NULL;
> unsigned int maskbits;
> - struct sdaddr *m, *n;
>
> /*
> * if a blacklist of same tag name is already there, replace it,
> @@ -67,12 +65,12 @@
> }
> if (idx != -1) {
> if (debug > 0)
> - printf("replacing list %s; %d new entries\n",
> - blacklists[idx].tag, addrc);
> + printf("replacing list %s; %u new entries\n",
> + blacklists[idx].tag, nv4 + nv6);
> sdl_free(&blacklists[idx]);
> } else {
> if (debug > 0)
> - printf("adding list %s; %d entries\n", sdname, addrc);
> + printf("adding list %s; %u entries\n", sdname, nv4 +
> nv6);
> if (blu == blc) {
> struct sdlist *tmp;
>
> @@ -92,62 +90,95 @@
> if ((blacklists[idx].string = strdup(sdstring)) == NULL)
> goto misc_error;
>
> - blacklists[idx].naddrs = addrc;
> -
> /*
> - * Cycle through addrs, converting. We assume they are correctly
> - * formatted v4 and v6 addrs, if they don't all convert correctly, the
> - * add fails. Each address should be address/maskbits
> + * Cycle through addrs by family, converting. We assume they are
> + * correctly formatted v4 and v6 addrs, if they don't all convert
> + * correctly, the add fails. Each address should be address/maskbits.
> */
> - blacklists[idx].addrs = calloc(addrc, sizeof(struct sdentry));
> - if (blacklists[idx].addrs == NULL)
> - goto misc_error;
> -
> - for (i = 0; i < addrc; i++) {
> - int j, k, af;
> -
> - n = &blacklists[idx].addrs[i].sda;
> - m = &blacklists[idx].addrs[i].sdm;
> + if (nv4 != 0) {
> + blacklists[idx].v4.naddrs = nv4;
> + blacklists[idx].v4.addrs = reallocarray(NULL, nv4,
> + sizeof(struct sdentry_v4));
> + if (blacklists[idx].v4.addrs == NULL)
> + goto misc_error;
> + for (i = 0; i < nv4; i++) {
> + struct in_addr *m, *n;
> + int j;
> +
> + n = &blacklists[idx].v4.addrs[i].sda;
> + m = &blacklists[idx].v4.addrs[i].sdm;
> +
> + addr = v4[i];
> + j = sscanf(addr, "%15[^/]/%u", astring, &maskbits);
> + if (j != 2)
> + goto parse_error;
> + /*
> + * sanity check! we don't allow a 0 mask -
> + * don't blacklist the entire net.
> + */
> + if (maskbits == 0 || maskbits > 32)
> + goto parse_error;
> + j = inet_pton(AF_INET, astring, n);
> + if (j != 1)
> + goto parse_error;
> + if (debug > 0)
> + printf("added %s/%u\n", astring, maskbits);
> +
> + /* set mask. */
> + m->s_addr = 0xffffffffU << (32 - maskbits);
> + m->s_addr = htonl(m->s_addr);
>
> - j = sscanf(addrs[i], "%39[^/]/%u", astring, &maskbits);
> - if (j != 2)
> - goto parse_error;
> - if (maskbits > 128)
> - goto parse_error;
> - /*
> - * sanity check! we don't allow a 0 mask -
> - * don't blacklist the entire net.
> - */
> - if (maskbits == 0)
> - goto parse_error;
> - if (strchr(astring, ':') != NULL)
> - af = AF_INET6;
> - else
> - af = AF_INET;
> - if (af == AF_INET && maskbits > 32)
> - goto parse_error;
> - j = inet_pton(af, astring, n);
> - if (j != 1)
> - goto parse_error;
> - if (debug > 0)
> - printf("added %s/%u\n", astring, maskbits);
> -
> - /* set mask, borrowed from pf */
> - k = 0;
> - for (j = 0; j < 4; j++)
> - m->addr32[j] = 0;
> - while (maskbits >= 32) {
> - m->addr32[k++] = 0xffffffff;
> - maskbits -= 32;
> + /* mask off address bits that won't ever be used */
> + n->s_addr = n->s_addr & m->s_addr;
> + }
> + }
> + if (nv6 != 0) {
> + blacklists[idx].v6.naddrs = nv6;
> + blacklists[idx].v6.addrs = reallocarray(NULL, nv6,
> + sizeof(struct sdentry_v6));
> + if (blacklists[idx].v6.addrs == NULL)
> + goto misc_error;
> +
> + for (i = 0; i < nv6; i++) {
> + int j, k;
> + struct sdaddr_v6 *m, *n;
> +
> + n = &blacklists[idx].v6.addrs[i].sda;
> + m = &blacklists[idx].v6.addrs[i].sdm;
> +
> + addr = v6[i];
> + j = sscanf(addr, "%39[^/]/%u", astring, &maskbits);
> + if (j != 2)
> + goto parse_error;
> + /*
> + * sanity check! we don't allow a 0 mask -
> + * don't blacklist the entire net.
> + */
> + if (maskbits == 0 || maskbits > 128)
> + goto parse_error;
> + j = inet_pton(AF_INET6, astring, n);
> + if (j != 1)
> + goto parse_error;
> + if (debug > 0)
> + printf("added %s/%u\n", astring, maskbits);
> +
> + /* set mask, borrowed from pf */
> + k = 0;
> + for (j = 0; j < 4; j++)
> + m->addr32[j] = 0;
> + while (maskbits >= 32) {
> + m->addr32[k++] = 0xffffffff;
> + maskbits -= 32;
> + }
> + for (j = 31; j > 31 - maskbits; --j)
> + m->addr32[k] |= (1 << j);
> + if (maskbits)
> + m->addr32[k] = htonl(m->addr32[k]);
> +
> + /* mask off address bits that won't ever be used */
> + for (j = 0; j < 4; j++)
> + n->addr32[j] = n->addr32[j] & m->addr32[j];
> }
> - for (j = 31; j > 31 - maskbits; --j)
> - m->addr32[k] |= (1 << j);
> - if (maskbits)
> - m->addr32[k] = htonl(m->addr32[k]);
> -
> - /* mask off address bits that won't ever be used */
> - for (j = 0; j < 4; j++)
> - n->addr32[j] = n->addr32[j] & m->addr32[j];
> }
> if (idx == blu) {
> blu++;
> @@ -156,7 +187,7 @@
> return (0);
> parse_error:
> if (debug > 0)
> - printf("sdl_add: parse error, \"%s\"\n", addrs[i]);
> + printf("sdl_add: parse error, \"%s\"\n", addr);
> misc_error:
> sdl_free(&blacklists[idx]);
> if (idx != blu) {
> @@ -181,11 +212,15 @@
> if (idx != -1) {
> if (debug > 0)
> printf("clearing list %s\n", sdname);
> + /* Must preserve tag. */
> free(blacklists[idx].string);
> - free(blacklists[idx].addrs);
> + free(blacklists[idx].v4.addrs);
> + free(blacklists[idx].v6.addrs);
> blacklists[idx].string = NULL;
> - blacklists[idx].addrs = NULL;
> - blacklists[idx].naddrs = 0;
> + blacklists[idx].v4.addrs = NULL;
> + blacklists[idx].v6.addrs = NULL;
> + blacklists[idx].v4.naddrs = 0;
> + blacklists[idx].v6.naddrs = 0;
> }
> }
>
> @@ -194,74 +229,86 @@
> * otherwise return 0. It is assumed that address a has been
> * pre-masked out, we only need to mask b.
> */
> -int
> -match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b,
> - sa_family_t af)
> +static int
> +match_addr_v4(struct in_addr *a, struct in_addr *m, struct in_addr *b)
> {
> - int match = 0;
> -
> - switch (af) {
> - case AF_INET:
> - if ((a->addr32[0]) ==
> - (b->addr32[0] & m->addr32[0]))
> - match++;
> - break;
> - case AF_INET6:
> - if (((a->addr32[0]) ==
> - (b->addr32[0] & m->addr32[0])) &&
> - ((a->addr32[1]) ==
> - (b->addr32[1] & m->addr32[1])) &&
> - ((a->addr32[2]) ==
> - (b->addr32[2] & m->addr32[2])) &&
> - ((a->addr32[3]) ==
> - (b->addr32[3] & m->addr32[3])))
> - match++;
> - break;
> - }
> - return (match);
> + if (a->s_addr == (b->s_addr & m->s_addr))
> + return (1);
> + return (0);
> }
>
> -
> /*
> - * Given an address and address family
> - * return list of pointers to matching nodes. or NULL if none.
> + * Return 1 if the addresses a (with mask m) matches address b
> + * otherwise return 0. It is assumed that address a has been
> + * pre-masked out, we only need to mask b.
> */
> -struct sdlist **
> -sdl_lookup(struct sdlist *head, int af, void * src)
> +static int
> +match_addr_v6(struct sdaddr_v6 *a, struct sdaddr_v6 *m, struct sdaddr_v6 *b)
> {
> + if (((a->addr32[0]) == (b->addr32[0] & m->addr32[0])) &&
> + ((a->addr32[1]) == (b->addr32[1] & m->addr32[1])) &&
> + ((a->addr32[2]) == (b->addr32[2] & m->addr32[2])) &&
> + ((a->addr32[3]) == (b->addr32[3] & m->addr32[3])))
> + return (1);
> + return (0);
> +}
> +
> +#define grow_sdlist(sd, c, l) do {
> \
> + if (c == l) {
> \
> + struct sdlist **tmp;
> \
> +
> \
> + tmp = reallocarray(sd, l + 128, sizeof(struct sdlist *));
> \
> + if (tmp == NULL) {
> \
> + /*
> \
> + * XXX out of memory - return what we have
> \
> + */
> \
> + return (sdnew);
> \
> + }
> \
> + sd = tmp;
> \
> + l += 128;
> \
> + }
> \
> +} while (0)
> +
> +static struct sdlist **
> +sdl_lookup_v4(struct sdlist *sdl, struct in_addr *src)
> +{
> + struct sdentry_v4 *entry;
> + int i, matches = 0;
> + int sdnewlen = 0;
> + struct sdlist **sdnew = NULL;
> +
> + while (sdl->tag != NULL) {
> + for (i = 0; i < sdl->v4.naddrs; i++) {
> + entry = &sdl->v4.addrs[i];
> + if (match_addr_v4(&entry->sda, &entry->sdm, src)) {
> + grow_sdlist(sdnew, matches, sdnewlen);
> + sdnew[matches] = sdl;
> + matches++;
> + sdnew[matches] = NULL;
> + break;
> + }
> + }
> + sdl++;
> + }
> + return (sdnew);
> +}
> +
> +static struct sdlist **
> +sdl_lookup_v6(struct sdlist *sdl, struct sdaddr_v6 *src)
> +{
> + struct sdentry_v6 *entry;
> int i, matches = 0;
> - struct sdlist *sdl;
> - struct sdentry *sda;
> - struct sdaddr *source = (struct sdaddr *) src;
> int sdnewlen = 0;
> struct sdlist **sdnew = NULL;
>
> - if (head == NULL)
> - return (NULL);
> - else
> - sdl = head;
> while (sdl->tag != NULL) {
> - for (i = 0; i < sdl->naddrs; i++) {
> - sda = sdl->addrs + i;
> - if (match_addr(&sda->sda, &sda->sdm, source, af)) {
> - if (matches == sdnewlen) {
> - struct sdlist **tmp;
> -
> - tmp = reallocarray(sdnew,
> - sdnewlen + 128,
> - sizeof(struct sdlist *));
> - if (tmp == NULL)
> - /*
> - * XXX out of memory -
> - * return what we have
> - */
> - return (sdnew);
> - sdnew = tmp;
> - sdnewlen += 128;
> - }
> - sdnew[matches]= sdl;
> + for (i = 0; i < sdl->v6.naddrs; i++) {
> + entry = &sdl->v6.addrs[i];
> + if (match_addr_v6(&entry->sda, &entry->sdm, src)) {
> + grow_sdlist(sdnew, matches, sdnewlen);
> + sdnew[matches] = sdl;
> matches++;
> - sdnew[matches]=NULL;
> + sdnew[matches] = NULL;
> break;
> }
> }
> @@ -270,12 +317,33 @@
> return (sdnew);
> }
>
> +/*
> + * Given an address and address family
> + * return list of pointers to matching nodes. or NULL if none.
> + */
> +struct sdlist **
> +sdl_lookup(struct sdlist *head, int af, void *src)
> +{
> + if (head == NULL)
> + return (NULL);
> +
> + switch (af) {
> + case AF_INET:
> + return (sdl_lookup_v4(head, src));
> + case AF_INET6:
> + return (sdl_lookup_v6(head, src));
> + default:
> + return (NULL);
> + }
> +}
> +
> static void
> sdl_free(struct sdlist *sdl)
> {
> free(sdl->tag);
> free(sdl->string);
> - free(sdl->addrs);
> + free(sdl->v4.addrs);
> + free(sdl->v6.addrs);
> sdl_clear(sdl);
> }
>
> @@ -284,7 +352,8 @@
> {
> sdl->tag = NULL;
> sdl->string = NULL;
> - sdl->addrs = NULL;
> - sdl->naddrs = 0;
> + sdl->v4.addrs = NULL;
> + sdl->v4.naddrs = 0;
> + sdl->v6.addrs = NULL;
> + sdl->v6.naddrs = 0;
> }
> -
> Index: libexec/spamd/sdl.h
> ===================================================================
> RCS file: /cvs/src/libexec/spamd/sdl.h,v
> retrieving revision 1.6
> diff -u -r1.6 sdl.h
> --- libexec/spamd/sdl.h 3 Nov 2007 19:16:07 -0000 1.6
> +++ libexec/spamd/sdl.h 9 Jan 2015 13:38:08 -0000
> @@ -22,40 +22,46 @@
> #include <sys/types.h>
> #include <sys/socket.h>
>
> -/* spamd source list */
> -struct sdlist {
> - char *tag; /* sdlist source name */
> - char *string; /* Format (451) string with no smtp code or \r\n */
> - struct sdentry *addrs;
> - size_t naddrs;
> +/* spamd netblock (black) list entry (ipv4) */
> +struct sdentry_v4 {
> + struct in_addr sda;
> + struct in_addr sdm;
> };
>
> -/* yeah. Stolen from pf */
> -struct sdaddr {
> +struct sdentries_v4 {
> + struct sdentry_v4 *addrs;
> + u_int naddrs;
> +};
> +
> +struct sdaddr_v6 {
> union {
> - struct in_addr v4;
> - struct in6_addr v6;
> - u_int8_t addr8[16];
> - u_int16_t addr16[8];
> + struct in6_addr addr;
> u_int32_t addr32[4];
> } _sda; /* 128-bit address */
> -#define v4 _sda.v4
> -#define v6 _sda.v6
> -#define addr8 _sda.addr8
> -#define addr16 _sda.addr16
> -#define addr32 _sda.addr32
> +#define addr32 _sda.addr32
> };
>
> -/* spamd netblock (black) list */
> -struct sdentry {
> - struct sdaddr sda;
> - struct sdaddr sdm;
> +/* spamd netblock (black) list entry (ipv6) */
> +struct sdentry_v6 {
> + struct sdaddr_v6 sda;
> + struct sdaddr_v6 sdm;
> };
>
> +struct sdentries_v6 {
> + struct sdentry_v6 *addrs;
> + u_int naddrs;
> +};
> +
> +/* spamd source list */
> +struct sdlist {
> + char *tag; /* sdlist source name */
> + char *string; /* Format (451) string with no smtp code or \r\n */
> + struct sdentries_v4 v4;
> + struct sdentries_v6 v6;
> +};
>
> -extern int sdl_add(char *, char *, char **, int);
> -extern void sdl_del(char *);
> -extern struct sdlist **sdl_lookup(struct sdlist *head,
> - int af, void * src);
> +int sdl_add(char *, char *, char **, u_int, char **, u_int);
> +void sdl_del(char *);
> +struct sdlist **sdl_lookup(struct sdlist *head, int af, void * src);
>
> #endif /* _SDL_H_ */
> Index: libexec/spamd/spamd.c
> ===================================================================
> RCS file: /cvs/src/libexec/spamd/spamd.c,v
> retrieving revision 1.118
> diff -u -r1.118 spamd.c
> --- libexec/spamd/spamd.c 30 Dec 2014 23:27:23 -0000 1.118
> +++ libexec/spamd/spamd.c 9 Jan 2015 13:38:08 -0000
> @@ -29,6 +29,7 @@
> #include <errno.h>
> #include <fcntl.h>
> #include <getopt.h>
> +#include <limits.h>
> #include <pwd.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -184,11 +185,12 @@
> int
> parse_configline(char *line)
> {
> - char *cp, prev, *name, *msg;
> - static char **av = NULL;
> - static size_t ac = 0;
> - size_t au = 0;
> + char *cp, prev, *name, *msg, *tmp;
> + char **v4 = NULL, **v6 = NULL;
> + const char *errstr;
> + u_int nv4 = 0, nv6 = 0;
> int mdone = 0;
> + sa_family_t af;
>
> name = line;
>
> @@ -219,11 +221,16 @@
> if (*cp == ';') {
> mdone = 1;
> *cp = '\0';
> - } else
> + } else {
> + if (debug > 0)
> + printf("bad message: %s\n",
> msg);
> goto parse_error;
> + }
> }
> break;
> case '\0':
> + if (debug > 0)
> + printf("bad message: %s\n", msg);
> goto parse_error;
> default:
> prev = '\0';
> @@ -231,35 +238,89 @@
> }
> }
>
> - do {
> - if (ac == au) {
> - char **tmp;
> + while ((tmp = strsep(&cp, ";")) != NULL) {
> + char **av;
> + u_int au, ac;
>
> - tmp = reallocarray(av, ac + 2048, sizeof(char *));
> - if (tmp == NULL) {
> - free(av);
> - av = NULL;
> - ac = 0;
> - return (-1);
> + if (*tmp == '\0')
> + continue;
> +
> + if (strncmp(tmp, "inet", 4) != 0)
> + goto parse_error;
> + switch (tmp[4]) {
> + case '\0':
> + af = AF_INET;
> + break;
> + case '6':
> + if (tmp[5] == '\0') {
> + af = AF_INET6;
> + break;
> }
> - av = tmp;
> - ac += 2048;
> + /* FALLTHROUGH */
> + default:
> + if (debug > 0)
> + printf("unsupported address family: %s\n",
> tmp);
> + goto parse_error;
> }
> - } while ((av[au++] = strsep(&cp, ";")) != NULL);
>
> - /* toss empty last entry to allow for trailing ; */
> - while (au > 0 && (av[au - 1] == NULL || av[au - 1][0] == '\0'))
> - au--;
> + tmp = strsep(&cp, ";");
> + if (tmp == NULL) {
> + if (debug > 0)
> + printf("missing address count\n");
> + goto parse_error;
> + }
> + ac = strtonum(tmp, 0, UINT_MAX, &errstr);
> + if (errstr != NULL) {
> + if (debug > 0)
> + printf("count \"%s\" is %s\n", tmp, errstr);
> + goto parse_error;
> + }
>
> - if (au < 1)
> + av = reallocarray(NULL, ac, sizeof(char *));
> + for (au = 0; au < ac; au++) {
> + tmp = strsep(&cp, ";");
> + if (tmp == NULL) {
> + if (debug > 0)
> + printf("expected %u addrs, got %u\n",
> + ac, au + 1);
> + free(av);
> + goto parse_error;
> + }
> + if (*tmp == '\0')
> + continue;
> + av[au] = tmp;
> + }
> + if (af == AF_INET) {
> + if (debug > 0)
> + printf("duplicate inet\n");
> + if (v4 != NULL)
> + goto parse_error;
> + v4 = av;
> + nv4 = ac;
> + } else {
> + if (debug > 0)
> + printf("duplicate inet6\n");
> + if (v6 != NULL)
> + goto parse_error;
> + v6 = av;
> + nv6 = ac;
> + }
> + }
> + if (nv4 == 0 && nv6 == 0) {
> + if (debug > 0)
> + printf("no addresses\n");
> goto parse_error;
> - else
> - sdl_add(name, msg, av, au);
> + }
> + sdl_add(name, msg, v4, nv4, v6, nv6);
> + free(v4);
> + free(v6);
> return (0);
>
> parse_error:
> if (debug > 0)
> - printf("bogus config line - need
> 'tag;message;a/m;a/m;a/m...'\n");
> + printf("bogus config line - need
> 'tag;message;af;count;a/m;a/m;a/m...'\n");
> + free(v4);
> + free(v6);
> return (-1);
> }
>
> Index: libexec/spamd-setup/spamd-setup.c
> ===================================================================
> RCS file: /cvs/src/libexec/spamd-setup/spamd-setup.c,v
> retrieving revision 1.39
> diff -u -r1.39 spamd-setup.c
> --- libexec/spamd-setup/spamd-setup.c 9 Oct 2014 02:43:43 -0000 1.39
> +++ libexec/spamd-setup/spamd-setup.c 8 Jan 2015 21:27:00 -0000
> @@ -60,13 +60,12 @@
> struct bl *bl;
> size_t blc, bls;
> u_int8_t black;
> - int count;
> };
>
> u_int32_t imask(u_int8_t);
> u_int8_t maxblock(u_int32_t, u_int8_t);
> u_int8_t maxdiff(u_int32_t, u_int32_t);
> -struct cidr *range2cidrlist(struct cidr *, int *, int *, u_int32_t,
> +struct cidr *range2cidrlist(struct cidr *, u_int *, u_int *, u_int32_t,
> u_int32_t);
> void cidr2range(struct cidr, u_int32_t *, u_int32_t *);
> char *atop(u_int32_t);
> @@ -78,8 +77,8 @@
> void do_message(FILE *, char *);
> struct bl *add_blacklist(struct bl *, size_t *, size_t *, gzFile, int);
> int cmpbl(const void *, const void *);
> -struct cidr *collapse_blacklist(struct bl *, size_t);
> -int configure_spamd(u_short, char *, char *, struct cidr *);
> +struct cidr *collapse_blacklist(struct bl *, size_t, u_int *);
> +int configure_spamd(u_short, char *, char *, struct cidr *,
> u_int);
> int configure_pf(struct cidr *);
> int getlist(char **, char *, struct blacklist *, struct
> blacklist *);
> __dead void usage(void);
> @@ -131,7 +130,7 @@
> }
>
> struct cidr *
> -range2cidrlist(struct cidr *list, int *cli, int *cls, u_int32_t start,
> +range2cidrlist(struct cidr *list, u_int *cli, u_int *cls, u_int32_t start,
> u_int32_t end)
> {
> u_int8_t maxsize, diff;
> @@ -536,9 +535,10 @@
> * printable form to pfctl or spamd.
> */
> struct cidr *
> -collapse_blacklist(struct bl *bl, size_t blc)
> +collapse_blacklist(struct bl *bl, size_t blc, u_int *clc)
> {
> - int bs = 0, ws = 0, state=0, cli, cls, i;
> + int bs = 0, ws = 0, state=0;
> + u_int cli, cls, i;
> u_int32_t bstart = 0;
> struct cidr *cl;
> int laststate;
> @@ -579,12 +579,13 @@
> laststate = state;
> }
> cl[cli].addr = 0;
> + *clc = cli;
> return (cl);
> }
>
> int
> configure_spamd(u_short dport, char *name, char *message,
> - struct cidr *blacklists)
> + struct cidr *blacklists, u_int count)
> {
> int lport = IPPORT_RESERVED - 1, s;
> struct sockaddr_in sin;
> @@ -605,8 +606,9 @@
> close(s);
> return (-1);
> }
> - fprintf(sdc, "%s", name);
> + fputs(name, sdc);
> do_message(sdc, message);
> + fprintf(sdc, ";inet;%u", count);
> while (blacklists->addr != 0) {
> fprintf(sdc, ";%s/%u", atop(blacklists->addr),
> blacklists->bits);
> @@ -757,14 +759,15 @@
> send_blacklist(struct blacklist *blist, in_port_t port)
> {
> struct cidr *cidrs;
> + u_int clc;
>
> if (blist->blc > 0) {
> - cidrs = collapse_blacklist(blist->bl, blist->blc);
> + cidrs = collapse_blacklist(blist->bl, blist->blc, &clc);
> if (cidrs == NULL)
> errx(1, "malloc failed");
> if (!dryrun) {
> if (configure_spamd(port, blist->name,
> - blist->message, cidrs) == -1)
> + blist->message, cidrs, clc) == -1)
> err(1, "Can't connect to spamd on port %d",
> port);
> if (!greyonly && configure_pf(cidrs) == -1)
>