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)
>

Reply via email to