? spamd-setup Index: spamd-setup.c =================================================================== RCS file: /cvs/src/libexec/spamd-setup/spamd-setup.c,v retrieving revision 1.47 diff -u -p -u -r1.47 spamd-setup.c --- spamd-setup.c 12 Dec 2015 20:09:28 -0000 1.47 +++ spamd-setup.c 12 Jan 2016 01:37:04 -0000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -42,22 +43,40 @@ #define PATH_SPAMD_CONF "/etc/mail/spamd.conf" #define SPAMD_ARG_MAX 256 /* max # of args to an exec */ +struct sda6 { + union { + struct in6_addr addr; + u_int32_t addr32[4]; + } _sda6; +#define addr32 _sda6.addr32 +}; + struct cidr { - u_int32_t addr; + union { + u_int32_t addr4; + struct sda6 addr6; + } _addr; u_int8_t bits; }; struct bl { - u_int32_t addr; + union { + u_int32_t addr4; + struct sda6 addr6; + } _addr; int8_t b; int8_t w; }; +#define addr4 _addr.addr4 +#define addr6 _addr.addr6 struct blacklist { char *name; char *message; struct bl *bl; size_t blc, bls; + struct bl *bl6; + size_t blc6, bls6; u_int8_t black; }; @@ -66,19 +85,30 @@ 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 *, u_int *, u_int *, u_int32_t, u_int32_t); +struct cidr *range2cidrlist6(struct cidr *, u_int *, u_int *, struct sda6 *, + struct sda6 *); void cidr2range(struct cidr, u_int32_t *, u_int32_t *); +void cidr2range6(struct cidr, struct sda6 *, struct sda6 *); char *atop(u_int32_t); -int parse_netblock(char *, struct bl *, struct bl *, int); +int parse_netblock(char *, struct bl *, struct bl *, struct bl*, + struct bl *, int); int open_child(char *, char **); int fileget(char *); int open_file(char *, char *); char *fix_quoted_colons(char *); void do_message(FILE *, char *); -struct bl *add_blacklist(struct bl *, size_t *, size_t *, gzFile, int); +int add_blacklist(struct bl **, size_t *, size_t *, struct bl **, + size_t *, size_t *, gzFile, int); +int cmp_ipv6(const struct sda6 *, const struct sda6 *); int cmpbl(const void *, const void *); -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 cmpbl6(const void *, const void *); +int collapse_blacklist(struct bl *, size_t, struct bl *, size_t, + struct cidr **, u_int *, struct cidr **, u_int *); +struct cidr *collapse_blacklist4(struct bl *, size_t, u_int *); +struct cidr *collapse_blacklist6(struct bl *, size_t, u_int *); +int configure_spamd(u_short, char *, char *, struct cidr *, u_int, + struct cidr *, u_int); +int configure_pf(struct cidr *, u_int, struct cidr *, u_int); int getlist(char **, char *, struct blacklist *, struct blacklist *); __dead void usage(void); @@ -89,6 +119,77 @@ int greyonly = 1; extern char *__progname; #define MAXIMUM(a,b) (((a)>(b))?(a):(b)) +#define MINIMUM(a,b) (((a)<(b))?(a):(b)) + +void +ipv6_add(struct sda6 *addr, u_int8_t num) +{ + int i; + u_int8_t carry; + u_int32_t tmp; + + for (i = 3; i >= 0; i--) { + if (num == 0) + break; + + tmp = ntohl(addr->addr32[i]); + if (num > (UINT32_MAX - tmp)) + carry = 1; + else + carry = 0; + + addr->addr32[i] = htonl(tmp + num); + num = carry; + } +} + +void +ipv6_add2(struct sda6 *addr, struct sda6 *src) +{ + int i, j; + u_int8_t carry; + u_int32_t num, tmp; + + for (i = 3; i >= 0; i--) { + num = ntohl(src->addr32[i]); + + for (j = i; j >= 0; j--) { + if (num == 0) + break; + + tmp = ntohl(addr->addr32[j]); + if (num > (UINT32_MAX - tmp)) + carry = 1; + else + carry = 0; + + addr->addr32[j] = htonl(tmp + num); + num = carry; + } + } +} + +void +ipv6_sub(struct sda6 *addr, u_int8_t num) +{ + int i; + u_int8_t carry; + u_int32_t tmp; + + for (i = 3; i >= 0; i--) { + if (num == 0) + break; + + tmp = ntohl(addr->addr32[i]); + if (num > tmp) + carry = 1; + else + carry = 0; + + addr->addr32[i] = htonl(tmp - num); + num = carry; + } +} u_int32_t imask(u_int8_t b) @@ -98,6 +199,24 @@ imask(u_int8_t b) return (0xffffffffU << (32 - b)); } +void +imask6(struct sda6 *m, u_int8_t b) +{ + int i; + u_int8_t tmp; + memset(m, 0, sizeof(struct sda6)); + + for (i = 0; i < 4; i++) { + if (b == 0) + break; + + tmp = MINIMUM(b, 32); + b -= tmp; + + m->addr32[i] = htonl(0xffffffffU << (32 - tmp)); + } +} + u_int8_t maxblock(u_int32_t addr, u_int8_t bits) { @@ -114,6 +233,26 @@ maxblock(u_int32_t addr, u_int8_t bits) } u_int8_t +maxblock6(struct sda6 *addr, u_int8_t bits) +{ + struct sda6 m; + int i; + + while (bits > 0) { + imask6(&m, bits - 1); + + for (i = 0; i < 4; i++) { + if ((addr->addr32[i] & m.addr32[i]) != addr->addr32[i]) { + return bits; + } + } + + bits--; + } + return (bits); +} + +u_int8_t maxdiff(u_int32_t a, u_int32_t b) { u_int8_t bits = 0; @@ -130,6 +269,28 @@ maxdiff(u_int32_t a, u_int32_t b) return (bits); } +u_int8_t +maxdiff6(struct sda6 *a, struct sda6 *b) +{ + u_int8_t bits = 0; + struct sda6 m, tmp; + int i; + + memcpy(&tmp, b, sizeof(tmp)); + + ipv6_add(&tmp, 1); + while (bits < 128) { + imask6(&m, bits); + + for (i = 0; i < 4; i++) { + if ((a->addr32[i] & m.addr32[i]) != (tmp.addr32[i] & m.addr32[i])) + return (bits); + } + bits++; + } + return (bits); +} + struct cidr * range2cidrlist(struct cidr *list, u_int *cli, u_int *cls, u_int32_t start, u_int32_t end) @@ -150,7 +311,7 @@ range2cidrlist(struct cidr *list, u_int list = tmp; *cls += 32; } - list[*cli].addr = start; + list[*cli].addr4 = start; list[*cli].bits = maxsize; (*cli)++; start = start + (1 << (32 - maxsize)); @@ -158,11 +319,81 @@ range2cidrlist(struct cidr *list, u_int return (list); } +struct cidr * +range2cidrlist6(struct cidr *list, u_int *cli, u_int *cls, struct sda6 *start, + struct sda6 *end) +{ + u_int8_t maxsize, diff, btmp; + struct cidr *tmp; + struct sda6 mask; + int i; + + while (cmp_ipv6(end, start) >= 0) { + maxsize = maxblock6(start, 128); + diff = maxdiff6(start, end); + + maxsize = MAXIMUM(maxsize, diff); + if (*cls <= *cli + 1) { + tmp = reallocarray(list, *cls + 32, + sizeof(struct cidr)); + if (tmp == NULL) + err(1, NULL); + list = tmp; + *cls += 32; + } + memcpy(&list[*cli].addr6, start, + sizeof(list[*cli].addr6)); + list[*cli].bits = maxsize; + (*cli)++; + + maxsize = 128 - maxsize; + + memset(&mask, 0, sizeof(mask)); + for (i = 3; i >= 0; i--) { + if (maxsize == 0) + break; + + btmp = MINIMUM(maxsize, 32); + maxsize -= btmp; + + mask.addr32[i] = htonl(0xffffffffU >> (32 - btmp)); + } + + ipv6_add(&mask, 1); + ipv6_add2(start, &mask); + } + + return (list); +} + void cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end) { - *start = cidr.addr; - *end = cidr.addr + (1 << (32 - cidr.bits)) - 1; + *start = cidr.addr4; + *end = cidr.addr4 + (1 << (32 - cidr.bits)) - 1; +} + +void +cidr2range6(struct cidr cidr, struct sda6 *start, struct sda6 *end) +{ + int i; + u_int8_t tmp, bits = 128 - cidr.bits; + struct sda6 mask; + memset(&mask, 0, sizeof(mask)); + + memcpy(start, &cidr.addr6, sizeof(cidr.addr6)); + memcpy(end, &cidr.addr6, sizeof(cidr.addr6)); + + for (i = 3; i >= 0; i--) { + if (bits == 0) + break; + + tmp = MINIMUM(bits, 32); + bits -= tmp; + mask.addr32[i] = htonl(0xffffffffU >> (32 - tmp)); + } + + ipv6_add2(end, &mask); } char * @@ -176,11 +407,13 @@ atop(u_int32_t addr) } int -parse_netblock(char *buf, struct bl *start, struct bl *end, int white) +parse_netblock(char *buf, struct bl *start, struct bl *end, struct bl *start6, + struct bl *end6, int white) { - char astring[16], astring2[16]; + char astring[40], astring2[40]; unsigned maskbits; struct cidr c; + int ret = 0; /* skip leading spaces */ while (*buf == ' ') @@ -189,56 +422,118 @@ parse_netblock(char *buf, struct bl *sta if (*buf == '#') return (0); /* otherwise, look for a netblock of some sort */ - if (sscanf(buf, "%15[^/]/%u", astring, &maskbits) == 2) { - /* looks like a cidr */ - memset(&c.addr, 0, sizeof(c.addr)); - if (inet_net_pton(AF_INET, astring, &c.addr, sizeof(c.addr)) - == -1) + if (sscanf(buf, "%15[0123456789.]/%u", astring, &maskbits) == 2) { + /* looks like IPv4 cidr */ + memset(&c.addr4, 0, sizeof(c.addr4)); + if (inet_net_pton(AF_INET, astring, &c.addr4, + sizeof(c.addr4)) == -1) return (0); - c.addr = ntohl(c.addr); + c.addr4 = ntohl(c.addr4); if (maskbits > 32) return (0); c.bits = maskbits; - cidr2range(c, &start->addr, &end->addr); - end->addr += 1; + cidr2range(c, &start->addr4, &end->addr4); + end->addr4 += 1; + + ret = AF_INET; + } else if (sscanf(buf, "%39[0123456789ABCDEFabcdef:]/%u", + astring, &maskbits) == 2) { + /* looks like IPv6 cidr */ + memset(&c.addr6, 0, sizeof(c.addr6)); + if (inet_net_pton(AF_INET6, astring, &c.addr6, + sizeof(c.addr6)) == -1) + return (0); + if (maskbits > 128) + return (0); + c.bits = maskbits; + cidr2range6(c, &start6->addr6, &end6->addr6); + ipv6_add(&end6->addr6, 1); + + ret = AF_INET6; } else if (sscanf(buf, "%15[0123456789.]%*[ -]%15[0123456789.]", astring, astring2) == 2) { - /* looks like start - end */ - memset(&start->addr, 0, sizeof(start->addr)); - memset(&end->addr, 0, sizeof(end->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return (0); - start->addr = ntohl(start->addr); - if (inet_net_pton(AF_INET, astring2, &end->addr, - sizeof(end->addr)) == -1) + /* looks like IPv4 start - end */ + memset(&start->addr4, 0, sizeof(start->addr4)); + memset(&end->addr4, 0, sizeof(end->addr4)); + if (inet_net_pton(AF_INET, astring, &start->addr4, + sizeof(start->addr4)) == -1) return (0); - end->addr = ntohl(end->addr) + 1; + start->addr4 = ntohl(start->addr4); + if (inet_net_pton(AF_INET, astring2, &end->addr4, + sizeof(end->addr4)) == -1) + return (0); + end->addr4 = ntohl(end->addr4) + 1; if (start > end) return (0); + + ret = AF_INET; + } else if (sscanf(buf, "%39[0123456789ABCDEFabcdef:]%*[ -]" + "%39[0123456789ABCDEFabcdef:]", astring, astring2) == 2) { + /* loks like IPv6 start - end */ + memset(&start6->addr6, 0, sizeof(start6->addr6)); + memset(&end6->addr6, 0, sizeof(end6->addr6)); + if (inet_net_pton(AF_INET6, astring, &start6->addr6, + sizeof(start6->addr6)) == -1) + return (0); + if (inet_net_pton(AF_INET6, astring2, &end6->addr6, + sizeof(end6->addr6)) == -1) + return (0); + ipv6_add(&end6->addr6, 1); + if (start6 > end6) + return (0); + + ret = AF_INET6; } else if (sscanf(buf, "%15[0123456789.]", astring) == 1) { - /* just a single address */ - memset(&start->addr, 0, sizeof(start->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) + /* just a single IPv4 address */ + memset(&start->addr4, 0, sizeof(start->addr4)); + if (inet_net_pton(AF_INET, astring, &start->addr4, + sizeof(start->addr4)) == -1) return (0); - start->addr = ntohl(start->addr); - end->addr = start->addr + 1; + start->addr4 = ntohl(start->addr4); + end->addr4 = start->addr4 + 1; + + ret = AF_INET; + } else if (sscanf(buf, "%39[0123456789ABCDEFabcdef:]", astring) == 1) { + /* just a single IPv6 address */ + memset(&start6->addr6, 0, sizeof(start6->addr6)); + if (inet_net_pton(AF_INET6, astring, &start6->addr6, + sizeof(start6->addr6)) == -1) + return (0); + memcpy(&end6->addr6, &start6->addr6, + sizeof(start6->addr6)); + + ipv6_add(&end6->addr6, 1); + + ret = AF_INET6; } else return (0); if (white) { - start->b = 0; - start->w = 1; - end->b = 0; - end->w = -1; + if (ret == AF_INET) { + start->b = 0; + start->w = 1; + end->b = 0; + end->w = -1; + } else { + start6->b = 0; + start6->w = 1; + end->b = 0; + end->w = -1; + } } else { - start->b = 1; - start->w = 0; - end->b = -1; - end->w = 0; + if (ret == AF_INET) { + start->b = 1; + start->w = 0; + end->b = -1; + end->w = 0; + } else { + start6->b = 1; + start6->w = 0; + end6->b = -1; + end6->w = 0; + } } - return (1); + return (ret); } int @@ -445,8 +740,9 @@ do_message(FILE *sdc, char *msg) } /* retrieve a list from fd. add to blacklist bl */ -struct bl * -add_blacklist(struct bl *bl, size_t *blc, size_t *bls, gzFile gzf, int white) +int +add_blacklist(struct bl **bl, size_t *blc, size_t *bls, struct bl **bl6, + size_t *blc6, size_t *bls6, gzFile gzf, int white) { int i, n, start, bu = 0, bs = 0, serrno = 0; char *buf = NULL, *tmp; @@ -481,30 +777,55 @@ add_blacklist(struct bl *bl, size_t *blc /* we assume that there is an IP for every 14 bytes */ if (*blc + bu / 7 >= *bls) { *bls += bu / 7; - blt = reallocarray(bl, *bls, sizeof(struct bl)); + blt = reallocarray(*bl, *bls, sizeof(struct bl)); if (blt == NULL) { *bls -= bu / 7; serrno = errno; goto bldone; } - bl = blt; + *bl = blt; + } + if (*blc6 + bu / 7 >= *bls6) { + *bls6 += bu / 7; + blt = reallocarray(*bl6, *bls6, sizeof(struct bl)); + if (blt == NULL) { + *bls6 -= bu / 7; + serrno = errno; + goto bldone; + } + *bl6 = blt; } for (i = 0; i <= bu; i++) { if (*blc + 1 >= *bls) { *bls += 1024; - blt = reallocarray(bl, *bls, sizeof(struct bl)); + blt = reallocarray(*bl, *bls, sizeof(struct bl)); if (blt == NULL) { *bls -= 1024; serrno = errno; goto bldone; } - bl = blt; + *bl = blt; + } + if (*blc6 + 1 >= *bls6) { + *bls6 += 1024; + blt = reallocarray(*bl6, *bls6, sizeof(struct bl)); + if (blt == NULL) { + *bls6 -= 1024; + serrno = errno; + goto bldone; + } + *bl6 = blt; } if (i == bu || buf[i] == '\n') { buf[i] = '\0'; - if (parse_netblock(buf + start, - bl + *blc, bl + *blc + 1, white)) + n = parse_netblock(buf + start, + *bl + *blc, *bl + *blc + 1, + *bl6 + *blc6, *bl6 + *blc6 + 1, white); + + if (n == AF_INET) *blc += 2; + else if (n == AF_INET6) + *blc6 += 2; start = i + 1; } } @@ -512,29 +833,83 @@ add_blacklist(struct bl *bl, size_t *blc errno = EIO; bldone: free(buf); - if (serrno) + if (serrno) { errno = serrno; - return (bl); + return (0); + } + return (1);; +} + +int +cmp_ipv6(const struct sda6 *a, const struct sda6 *b) +{ + int i; + u_int32_t atmp, btmp; + + for (i = 0; i < 4; i++) { + atmp = ntohl(a->addr32[i]); + btmp = ntohl(b->addr32[i]); + + if (atmp > btmp) + return (1); + if (atmp < btmp) + return (-1); + } + return (0); } int cmpbl(const void *a, const void *b) { - if (((struct bl *)a)->addr > ((struct bl *) b)->addr) + if (((struct bl *)a)->addr4 > ((struct bl *) b)->addr4) return (1); - if (((struct bl *)a)->addr < ((struct bl *) b)->addr) + if (((struct bl *)a)->addr4 < ((struct bl *) b)->addr4) return (-1); return (0); } +int +cmpbl6(const void *a, const void *b) +{ + struct sda6 *addr1, *addr2; + + addr1 = &((struct bl *)a)->addr6; + addr2 = &((struct bl *)b)->addr6; + + return cmp_ipv6(addr1, addr2); +} + /* * collapse_blacklist takes blacklist/whitelist entries sorts, removes * overlaps and whitelist portions, and returns netblocks to blacklist * as lists of nonoverlapping cidr blocks suitable for feeding in * printable form to pfctl or spamd. */ + +int +collapse_blacklist(struct bl *bl, size_t blc, struct bl *bl6, size_t blc6, + struct cidr **cidr, u_int *clc, struct cidr **cidr6, u_int *clc6) +{ + if (blc == 0 && blc6 == 0) + return (0); + + if (blc > 0) { + *cidr = collapse_blacklist4(bl, blc, clc); + if (*cidr == NULL) + return (0); + } + + if (blc6 > 0) { + *cidr6 = collapse_blacklist6(bl6, blc6, clc6); + if (*cidr6 == NULL) + return (0); + } + + return (1); +} + struct cidr * -collapse_blacklist(struct bl *bl, size_t blc, u_int *clc) +collapse_blacklist4(struct bl *bl, size_t blc, u_int *clc) { int bs = 0, ws = 0, state=0; u_int cli, cls, i; @@ -558,13 +933,13 @@ collapse_blacklist(struct bl *bl, size_t qsort(bl, blc, sizeof(struct bl), cmpbl); for (i = 0; i < blc;) { laststate = state; - addr = bl[i].addr; + addr = bl[i].addr4; do { bs += bl[i].b; ws += bl[i].w; i++; - } while (bl[i].addr == addr); + } while (bl[i].addr4 == addr); if (state == 1 && bs == 0) state = 0; else if (state == 0 && bs > 0) @@ -581,18 +956,73 @@ collapse_blacklist(struct bl *bl, size_t } laststate = state; } - cl[cli].addr = 0; + cl[cli].addr4 = 0; *clc = cli; return (cl); } +struct cidr * +collapse_blacklist6(struct bl *bl6, size_t blc6, u_int *clc6) +{ + int bs = 0, ws = 0, state = 0; + u_int cli, cls, i; + struct cidr *cl; + int laststate; + struct sda6 bstart, addr; + + memset(&bstart, 0, sizeof(bstart)); + + if (blc6 == 0) + return (NULL); + + cli = 0; + cls = (blc6 / 2) + (blc6 / 20) + 1; + cl = reallocarray(NULL, cls, sizeof(struct cidr)); + if (cl == NULL) + return (NULL); + qsort(bl6, blc6, sizeof(struct bl), cmpbl6); + + for (i = 0; i < blc6;) { + laststate = state; + memcpy(&addr, &bl6[i].addr6, sizeof(addr)); + + do { + bs += bl6[i].b; + ws += bl6[i].w; + i++; + } while (cmp_ipv6(&bl6[i].addr6, &addr) == 0); + if (state == 1 && bs == 0) + state = 0; + else if (state == 0 && bs > 0) + state = 1; + if (ws > 0) + state = 0; + if (laststate == 0 && state == 1) { + /* start blacklist */ + memcpy(&bstart, &addr, sizeof(addr)); + } + if (laststate == 1 && state == 0) { + /* end blacklist */ + ipv6_sub(&addr, 1); + cl = range2cidrlist6(cl, &cli, &cls, &bstart, &addr); + } + laststate = state; + } + + memset(&cl[cli].addr6, 0, sizeof(cl[cli].addr6)); + *clc6 = cli; + + return (cl); +} + int configure_spamd(u_short dport, char *name, char *message, - struct cidr *blacklists, u_int count) + struct cidr *blacklists, u_int count, struct cidr *blacklists6, u_int count6) { - int lport = IPPORT_RESERVED - 1, s; + int lport = IPPORT_RESERVED - 1, s, i; struct sockaddr_in sin; FILE* sdc; + char buf[INET6_ADDRSTRLEN]; s = rresvport(&lport); if (s == -1) @@ -612,10 +1042,14 @@ configure_spamd(u_short dport, char *nam 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); - blacklists++; + for (i = 0; i < count; i++) { + fprintf(sdc, ";%s/%u", atop(blacklists[i].addr4), + blacklists[i].bits); + } + fprintf(sdc, ";inet6;%u", count6); + for (i = 0; i < count6; i++) { + inet_ntop(AF_INET6, &blacklists6[i].addr6, buf, sizeof(buf)); + fprintf(sdc, ";%s/%u", buf, blacklists6[i].bits); } fputc('\n', sdc); fclose(sdc); @@ -625,12 +1059,14 @@ configure_spamd(u_short dport, char *nam int -configure_pf(struct cidr *blacklists) +configure_pf(struct cidr *blacklists, u_int count, struct cidr *blacklists6, + u_int count6) { char *argv[9]= {"pfctl", "-q", "-t", "spamd", "-T", "replace", "-f" "-", NULL}; + char buf[INET6_ADDRSTRLEN]; static FILE *pf = NULL; - int pdes[2]; + int pdes[2], i; if (pf == NULL) { if (pipe(pdes) != 0) @@ -659,10 +1095,13 @@ configure_pf(struct cidr *blacklists) return (-1); } } - while (blacklists->addr != 0) { - fprintf(pf, "%s/%u\n", atop(blacklists->addr), - blacklists->bits); - blacklists++; + for (i = 0; i < count; i++) { + fprintf(pf, "%s/%u\n", atop(blacklists[i].addr4), + blacklists[i].bits); + } + for (i = 0; i < count; i++) { + inet_ntop(AF_INET6, &blacklists6[i].addr6, buf, sizeof(buf)); + fprintf(pf, "%s/%u\n", buf, blacklists6[i].bits); } return (0); } @@ -672,9 +1111,10 @@ getlist(char ** db_array, char *name, st struct blacklist *blistnew) { char *buf, *method, *file, *message; - int fd, black = 0, serror; - size_t blc, bls; + int fd, black = 0, serror, ret; + size_t blc, bls, blc6, bls6; struct bl *bl = NULL; + struct bl *bl6 = NULL; gzFile gzf; if (cgetent(&buf, db_array, name) != 0) @@ -686,12 +1126,18 @@ getlist(char ** db_array, char *name, st blc = blistnew->blc; bls = blistnew->bls; bl = blistnew->bl; + blc6 = blistnew->blc6; + bls6 = blistnew->bls6; + bl6 = blistnew->bl6; } else if (cgetcap(buf, "white", ':') != NULL) { /* apply to most recent blacklist */ black = 0; blc = blist->blc; bls = blist->bls; bl = blist->bl; + blc6 = blist->blc6; + bls6 = blist->bls6; + bl6 = blist->bl6; } else errx(1, "Must have \"black\" or \"white\" in %s", name); @@ -730,10 +1176,10 @@ getlist(char ** db_array, char *name, st errx(1, "gzdopen"); } free(buf); - bl = add_blacklist(bl, &blc, &bls, gzf, !black); + ret = add_blacklist(&bl, &blc, &bls, &bl6, &blc6, &bls6, gzf, !black); serror = errno; gzclose(gzf); - if (bl == NULL) { + if (!ret) { errno = serror; warn("Could not add %slist %s", black ? "black" : "white", name); @@ -742,13 +1188,16 @@ getlist(char ** db_array, char *name, st if (black) { if (debug) fprintf(stderr, "blacklist %s %zu entries\n", - name, blc / 2); + name, ((blc / 2) + (blc6 / 2))); blistnew->message = message; blistnew->name = name; blistnew->black = black; blistnew->bl = bl; blistnew->blc = blc; blistnew->bls = bls; + blistnew->bl6 = bl6; + blistnew->blc6 = blc6; + blistnew->bls6 = bls6; } else { /* whitelist applied to last active blacklist */ if (debug) @@ -757,6 +1206,9 @@ getlist(char ** db_array, char *name, st blist->bl = bl; blist->blc = blc; blist->bls = bls; + blist->bl6 = bl6; + blist->blc6 = blc6; + blist->bls6 = bls6; } return (black); } @@ -764,22 +1216,24 @@ getlist(char ** db_array, char *name, st void send_blacklist(struct blacklist *blist, in_port_t port) { - struct cidr *cidrs; - u_int clc; + struct cidr *cidrs = NULL, *cidrs6 = NULL; + u_int clc = 0, clc6 = 0; - if (blist->blc > 0) { - cidrs = collapse_blacklist(blist->bl, blist->blc, &clc); - if (cidrs == NULL) + if (blist->blc > 0 || blist->blc6 > 0) { + if (!collapse_blacklist(blist->bl, blist->blc, blist->bl6, + blist->blc6, &cidrs, &clc, &cidrs6, &clc6)) err(1, NULL); if (!dryrun) { if (configure_spamd(port, blist->name, - blist->message, cidrs, clc) == -1) + blist->message, cidrs, clc, cidrs6, clc6) == -1) err(1, "Can't connect to spamd on port %d", port); - if (!greyonly && configure_pf(cidrs) == -1) + if (!greyonly && configure_pf(cidrs, clc, cidrs6, clc6) + == -1) err(1, "pfctl failed"); } free(cidrs); + free(cidrs6); free(blist->bl); } }