-/* $OpenBSD: spamd-setup.c,v 1.39 2014/10/09 02:43:43 deraadt Exp $ */
+/* $OpenBSD: spamd-setup.c,v 1.40 2015/01/13 21:42:59 millert Exp $ */
/*
* Copyright (c) 2003 Bob Beck. All rights reserved.
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);
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);
{
if (b == 0)
return (0);
- return (0xffffffff << (32 - b));
+ return (0xffffffffU << (32 - b));
}
u_int8_t
}
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;
* 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;
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;
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);
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)
-/* $OpenBSD: sdl.c,v 1.20 2015/01/08 22:10:08 millert Exp $ */
+/* $OpenBSD: sdl.c,v 1.21 2015/01/13 21:42:59 millert Exp $ */
/*
* Copyright (c) 2003-2007 Bob Beck. All rights reserved.
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,
}
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;
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;
+ 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;
- for (i = 0; i < addrc; i++) {
- int j, k, af;
-
- n = &blacklists[idx].addrs[i].sda;
- m = &blacklists[idx].addrs[i].sdm;
-
- 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;
+ 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);
+
+ /* 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++] = 0xffffffffU;
+ 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++;
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) {
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;
}
}
* 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;
- 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->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;
+ sdnew[matches] = NULL;
break;
}
}
return (sdnew);
}
+static struct sdlist **
+sdl_lookup_v6(struct sdlist *sdl, struct sdaddr_v6 *src)
+{
+ struct sdentry_v6 *entry;
+ int i, matches = 0;
+ int sdnewlen = 0;
+ struct sdlist **sdnew = NULL;
+
+ while (sdl->tag != NULL) {
+ 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;
+ break;
+ }
+ }
+ sdl++;
+ }
+ 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);
}
{
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;
}
-
-/* $OpenBSD: spamd.c,v 1.118 2014/12/30 23:27:23 millert Exp $ */
+/* $OpenBSD: spamd.c,v 1.119 2015/01/13 21:42:59 millert Exp $ */
/*
* Copyright (c) 2002-2007 Bob Beck. All rights reserved.
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
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;
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';
}
}
- 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);
}