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