From afc2c4818834efb1fd45c267515ef26e674f63f8 Mon Sep 17 00:00:00 2001 From: Marius Halden Date: Mon, 11 Jan 2016 01:37:26 +0100 Subject: initial --- spamd-setup.patch_1 | 939 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 939 insertions(+) create mode 100644 spamd-setup.patch_1 (limited to 'spamd-setup.patch_1') diff --git a/spamd-setup.patch_1 b/spamd-setup.patch_1 new file mode 100644 index 0000000..08b37cc --- /dev/null +++ b/spamd-setup.patch_1 @@ -0,0 +1,939 @@ +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 10 Jan 2016 19:23:12 -0000 +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -43,12 +44,20 @@ + #define SPAMD_ARG_MAX 256 /* max # of args to an exec */ + + struct cidr { +- u_int32_t addr; ++ sa_family_t ai_family; ++ union { ++ u_int32_t addr4; ++ u_int8_t addr6[16]; ++ } addr; + u_int8_t bits; + }; + + struct bl { +- u_int32_t addr; ++ sa_family_t ai_family; ++ union { ++ u_int32_t addr4; ++ u_int8_t addr6[16]; ++ } addr; + int8_t b; + int8_t w; + }; +@@ -58,6 +67,8 @@ struct blacklist { + char *message; + struct bl *bl; + size_t blc, bls; ++ struct bl *bl6; ++ size_t blc6, bls6; + u_int8_t black; + }; + +@@ -66,19 +77,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 *, u_int8_t *, ++ u_int8_t *); + void cidr2range(struct cidr, u_int32_t *, u_int32_t *); ++void cidr2range6(struct cidr, u_int8_t *, u_int8_t *); + 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 u_int8_t *, const u_int8_t *); + 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 +111,74 @@ 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(u_int8_t *addr, u_int8_t num) ++{ ++ int i; ++ u_int8_t tmp; ++ ++ for (i = 15; i >= 0; i--) { ++ if (num == 0) ++ break; ++ ++ if (num > (UINT8_MAX - addr[i])) ++ tmp = 1; ++ else ++ tmp = 0; ++ ++ addr[i] += num; ++ ++ num = tmp; ++ } ++} ++ ++void ++ipv6_add2(u_int8_t *addr, u_int8_t *src) ++{ ++ int i, j; ++ u_int8_t tmp, num; ++ ++ for (i = 15; i >= 0; i--) { ++ num = src[i]; ++ ++ for (j = i; j >= 0; j--) { ++ if (num == 0) ++ break; ++ ++ if (num > (UINT8_MAX - addr[j])) ++ tmp = 1; ++ else ++ tmp = 0; ++ ++ addr[j] += num; ++ ++ num = tmp; ++ } ++ } ++} ++ ++void ++ipv6_sub(u_int8_t *addr, u_int8_t num) ++{ ++ int i; ++ u_int8_t tmp; ++ ++ for (i = 15; i >= 0; i--) { ++ if (num == 0) ++ break; ++ ++ if (num > addr[i]) ++ tmp = 1; ++ else ++ tmp = 0; ++ ++ addr[i] -= num; ++ ++ num = tmp; ++ } ++} + + u_int32_t + imask(u_int8_t b) +@@ -98,6 +188,24 @@ imask(u_int8_t b) + return (0xffffffffU << (32 - b)); + } + ++void ++imask6(u_int8_t *m, u_int8_t b) ++{ ++ int i; ++ u_int8_t tmp; ++ memset(m, 0, sizeof(u_int8_t) * 16); ++ ++ for (i = 0; i < 16; i++) { ++ if (b == 0) ++ break; ++ ++ tmp = MINIMUM(b, 8); ++ b -= tmp; ++ ++ m[i] = (0xffU << (8 - tmp)); ++ } ++} ++ + u_int8_t + maxblock(u_int32_t addr, u_int8_t bits) + { +@@ -114,6 +222,26 @@ maxblock(u_int32_t addr, u_int8_t bits) + } + + u_int8_t ++maxblock6(u_int8_t *addr, u_int8_t bits) ++{ ++ u_int8_t m[16]; ++ int i; ++ ++ while (bits > 0) { ++ imask6(m, bits - 1); ++ ++ for (i = 0; i < 16; i++) { ++ if ((addr[i] & m[i]) != addr[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 +258,28 @@ maxdiff(u_int32_t a, u_int32_t b) + return (bits); + } + ++u_int8_t ++maxdiff6(u_int8_t *a, u_int8_t *b) ++{ ++ u_int8_t bits = 0; ++ u_int8_t m[16], tmp[16]; ++ int i; ++ ++ memcpy(tmp, b, sizeof(tmp)); ++ ++ ipv6_add(tmp, 1); ++ while (bits < 128) { ++ imask6(m, bits); ++ ++ for (i = 0; i < 15; i++) { ++ if ((a[i] & m[i]) != (tmp[i] & m[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 +300,7 @@ range2cidrlist(struct cidr *list, u_int + list = tmp; + *cls += 32; + } +- list[*cli].addr = start; ++ list[*cli].addr.addr4 = start; + list[*cli].bits = maxsize; + (*cli)++; + start = start + (1 << (32 - maxsize)); +@@ -158,11 +308,102 @@ range2cidrlist(struct cidr *list, u_int + return (list); + } + ++struct cidr * ++range2cidrlist6(struct cidr *list, u_int *cli, u_int *cls, u_int8_t *start, ++ u_int8_t *end) ++{ ++ u_int8_t maxsize, diff, btmp; ++ struct cidr *tmp; ++ int i; ++ ++ while (cmp_ipv6(end, start) >= 0) { ++ /*{ // XXX ++ char s[INET6_ADDRSTRLEN], e[INET6_ADDRSTRLEN]; ++ ++ inet_ntop(AF_INET6, start, s, sizeof(s)); ++ inet_ntop(AF_INET6, end, e, sizeof(e)); ++ ++ fprintf(stderr, "DEBUG: s=%s, e=%s\n", s, e); ++ }*/ ++ 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].addr.addr6, start, ++ sizeof(list[*cli].addr.addr6)); ++ list[*cli].bits = maxsize; ++ (*cli)++; ++ ++ maxsize = 128 - maxsize; ++ u_int8_t mask[16]; ++ memset(mask, 0, sizeof(mask)); ++ ++ for (i = 15; i >= 0; i--) { ++ btmp = ((maxsize < 8) ? maxsize : 8); ++ maxsize -= btmp; ++ ++ mask[i] = ((1 << btmp) - 1); ++ ++ if (maxsize == 0) ++ break; ++ } ++ ++ ipv6_add(mask, 1); ++ ipv6_add2(start, mask); ++ ++ /* { // XXX ++ char m[INET6_ADDRSTRLEN]; ++ ++ inet_ntop(AF_INET6, mask, m, sizeof(m)); ++ ++ fprintf(stderr, "DEBUG: m=%s\n", m); ++ }*/ ++ } ++ ++ 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.addr.addr4; ++ *end = cidr.addr.addr4 + (1 << (32 - cidr.bits)) - 1; ++} ++ ++void ++cidr2range6(struct cidr cidr, u_int8_t *start, u_int8_t *end) ++{ ++ int i; ++ u_int8_t tmp, bits = 128 - cidr.bits; ++ u_int8_t mask[16]; ++ memset(mask, 0, sizeof(mask)); ++ ++ for (i = 0; i < 16; i++) ++ end[i] = start[i] = cidr.addr.addr6[i]; ++ //start[i] = cidr.addr.addr6[i]; ++ ++ for (i = 15; i >= 0; i--) { ++ if (bits == 0) { ++ //end[i] = start[i]; ++ break; ++ } else { ++ tmp = MINIMUM(bits, 8); ++ bits -= tmp; ++ ++ //end[i] = start[i] + ((1 << tmp) - 1); // XXX ++ mask[i] = ((1 << tmp) - 1); ++ } ++ } ++ ++ ipv6_add2(end, mask); + } + + char * +@@ -176,11 +417,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 +432,130 @@ 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 */ ++ if (sscanf(buf, "%15[0123456789.]/%u", astring, &maskbits) == 2) { ++ /* looks like IPv4 cidr */ + memset(&c.addr, 0, sizeof(c.addr)); +- if (inet_net_pton(AF_INET, astring, &c.addr, sizeof(c.addr)) +- == -1) ++ if (inet_net_pton(AF_INET, astring, &c.addr.addr4, ++ sizeof(c.addr.addr4)) == -1) + return (0); +- c.addr = ntohl(c.addr); ++ c.ai_family = AF_INET; ++ c.addr.addr4 = ntohl(c.addr.addr4); + if (maskbits > 32) + return (0); + c.bits = maskbits; +- cidr2range(c, &start->addr, &end->addr); +- end->addr += 1; ++ cidr2range(c, &start->addr.addr4, &end->addr.addr4); ++ start->ai_family = end->ai_family = AF_INET; ++ end->addr.addr4 += 1; ++ ++ ret = AF_INET; ++ } else if (sscanf(buf, "%39[0123456789ABCDEFabcdef:]/%u", ++ astring, &maskbits) == 2) { ++ /* looks like IPv6 cidr */ ++ memset(&c.addr, 0, sizeof(c.addr)); ++ if (inet_net_pton(AF_INET6, astring, &c.addr.addr6, ++ sizeof(c.addr.addr6)) == -1) ++ return (0); ++ c.ai_family = AF_INET6; ++ if (maskbits > 128) ++ return (0); ++ c.bits = maskbits; ++ cidr2range6(c, start6->addr.addr6, end6->addr.addr6); ++ start6->ai_family = end6->ai_family = AF_INET6; ++ ipv6_add(end6->addr.addr6, 1); ++ ++ ret = AF_INET6; + } else if (sscanf(buf, "%15[0123456789.]%*[ -]%15[0123456789.]", + astring, astring2) == 2) { +- /* looks like start - end */ ++ /* looks like IPv4 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) ++ if (inet_net_pton(AF_INET, astring, &start->addr.addr4, ++ sizeof(start->addr.addr4)) == -1) + return (0); +- start->addr = ntohl(start->addr); +- if (inet_net_pton(AF_INET, astring2, &end->addr, +- sizeof(end->addr)) == -1) ++ start->ai_family = AF_INET; ++ start->addr.addr4 = ntohl(start->addr.addr4); ++ if (inet_net_pton(AF_INET, astring2, &end->addr.addr4, ++ sizeof(end->addr.addr4)) == -1) + return (0); +- end->addr = ntohl(end->addr) + 1; ++ end->ai_family = AF_INET; ++ end->addr.addr4 = ntohl(end->addr.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->addr, 0, sizeof(start6->addr)); ++ memset(&end6->addr, 0, sizeof(end6->addr)); ++ if (inet_net_pton(AF_INET6, astring, &start6->addr.addr6, ++ sizeof(start6->addr.addr6)) == -1) ++ return (0); ++ start6->ai_family = AF_INET6; ++ if (inet_net_pton(AF_INET6, astring2, &end6->addr.addr6, ++ sizeof(end6->addr.addr6)) == -1) ++ return (0); ++ end6->ai_family = AF_INET6; ++ ipv6_add(end6->addr.addr6, 1); ++ if (start6 > end6) ++ return (0); ++ ++ ret = AF_INET6; + } else if (sscanf(buf, "%15[0123456789.]", astring) == 1) { +- /* just a single address */ ++ /* just a single IPv4 address */ + memset(&start->addr, 0, sizeof(start->addr)); +- if (inet_net_pton(AF_INET, astring, &start->addr, +- sizeof(start->addr)) == -1) ++ if (inet_net_pton(AF_INET, astring, &start->addr.addr4, ++ sizeof(start->addr.addr4)) == -1) + return (0); +- start->addr = ntohl(start->addr); +- end->addr = start->addr + 1; ++ start->ai_family = AF_INET; ++ end->ai_family = AF_INET; ++ start->addr.addr4 = ntohl(start->addr.addr4); ++ end->addr.addr4 = start->addr.addr4 + 1; ++ ++ ret = AF_INET; ++ } else if (sscanf(buf, "%39[0123456789ABCDEFabcdef:]", astring) == 1) { ++ /* just a single IPv6 address */ ++ memset(&start6->addr, 0, sizeof(start6->addr)); ++ if (inet_net_pton(AF_INET6, astring, &start6->addr.addr6, ++ sizeof(start6->addr.addr6)) == -1) ++ return (0); ++ start6->ai_family = AF_INET6; ++ end6->ai_family = AF_INET6; ++ memcpy(&end6->addr.addr6, &start6->addr.addr6, ++ sizeof(start6->addr.addr6)); ++ ++ ipv6_add(end6->addr.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 +762,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 +799,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 +855,78 @@ 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 u_int8_t *a, const u_int8_t *b) ++{ ++ int i; ++ for (i = 0; i < 16; i++) { ++ if (a[i] > b[i]) ++ return (1); ++ if (a[i] < b[i]) ++ 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)->addr.addr4 > ((struct bl *) b)->addr.addr4) + return (1); +- if (((struct bl *)a)->addr < ((struct bl *) b)->addr) ++ if (((struct bl *)a)->addr.addr4 < ((struct bl *) b)->addr.addr4) + return (-1); + return (0); + } + ++int ++cmpbl6(const void *a, const void *b) ++{ ++ u_int8_t *addr1, *addr2; ++ ++ addr1 = ((struct bl *)a)->addr.addr6; ++ addr2 = ((struct bl *)b)->addr.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 +950,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].addr.addr4; + + do { + bs += bl[i].b; + ws += bl[i].w; + i++; +- } while (bl[i].addr == addr); ++ } while (bl[i].addr.addr4 == addr); + if (state == 1 && bs == 0) + state = 0; + else if (state == 0 && bs > 0) +@@ -581,18 +973,74 @@ collapse_blacklist(struct bl *bl, size_t + } + laststate = state; + } +- cl[cli].addr = 0; ++ cl[cli].addr.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; ++ u_int8_t bstart[16]; ++ u_int8_t addr[16]; ++ ++ 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].addr.addr6, sizeof(addr)); ++ ++ do { ++ bs += bl6[i].b; ++ ws += bl6[i].w; ++ i++; ++ } while (cmp_ipv6(bl6[i].addr.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].addr.addr6, 0, sizeof(cl[cli].addr.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 +1060,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].addr.addr4), ++ blacklists[i].bits); ++ } ++ fprintf(sdc, ";inet6;%u", count6); ++ for (i = 0; i < count6; i++) { ++ inet_ntop(AF_INET6, blacklists6[i].addr.addr6, buf, sizeof(buf)); ++ fprintf(sdc, ";%s/%u", buf, blacklists6[i].bits); + } + fputc('\n', sdc); + fclose(sdc); +@@ -625,12 +1077,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 +1113,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].addr.addr4), ++ blacklists[i].bits); ++ } ++ for (i = 0; i < count; i++) { ++ inet_ntop(AF_INET6, blacklists6[i].addr.addr6, buf, sizeof(buf)); ++ fprintf(pf, "%s/%u\n", buf, blacklists6[i].bits); + } + return (0); + } +@@ -672,9 +1129,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 +1144,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 +1194,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 +1206,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 +1224,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 +1234,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); + } + } -- cgit v1.2.3