summaryrefslogtreecommitdiffstats
path: root/spamd.patch
diff options
context:
space:
mode:
authorMarius Halden <marius.h@lden.org>2016-01-11 01:37:26 +0100
committerMarius Halden <marius.h@lden.org>2016-01-11 01:37:26 +0100
commitafc2c4818834efb1fd45c267515ef26e674f63f8 (patch)
treeef1f8d103a0bd852f16057c2f6d7e76bb2a626fd /spamd.patch
downloadspamd-patches-afc2c4818834efb1fd45c267515ef26e674f63f8.tar.gz
spamd-patches-afc2c4818834efb1fd45c267515ef26e674f63f8.tar.bz2
spamd-patches-afc2c4818834efb1fd45c267515ef26e674f63f8.tar.xz
initial
Diffstat (limited to 'spamd.patch')
-rw-r--r--spamd.patch938
1 files changed, 938 insertions, 0 deletions
diff --git a/spamd.patch b/spamd.patch
new file mode 100644
index 0000000..3e7c986
--- /dev/null
+++ b/spamd.patch
@@ -0,0 +1,938 @@
+Index: grey.c
+===================================================================
+RCS file: /cvs/src/libexec/spamd/grey.c,v
+retrieving revision 1.62
+diff -u -r1.62 grey.c
+--- grey.c 10 Dec 2015 16:06:29 -0000 1.62
++++ grey.c 31 Dec 2015 20:25:24 -0000
+@@ -54,8 +54,10 @@
+ #define satosin(sa) ((struct sockaddr_in *)(sa))
+ #define satosin6(sa) ((struct sockaddr_in6 *)(sa))
+
+-void configure_spamd(char **, u_int, FILE *);
+-int configure_pf(char **, int);
++struct listentry;
++
++void configure_spamd(struct listentry *, u_int, FILE *);
++int configure_pf(struct listentry *, int);
+ char *dequotetolower(const char *);
+ void readsuffixlists(void);
+ void freeaddrlists(void);
+@@ -69,11 +71,10 @@
+ int greyreader(void);
+ void greyscanner(void);
+
+-
+ u_int whitecount, whitealloc;
+ u_int trapcount, trapalloc;
+-char **whitelist;
+-char **traplist;
++struct listentry *whitelist;
++struct listentry *traplist;
+
+ char *traplist_name = "spamd-greytrap";
+ char *traplist_msg = "\"Your address %A has mailed to spamtraps here\\n\"";
+@@ -89,6 +90,18 @@
+ int act;
+ };
+
++struct listentry {
++ char *entry;
++ int af;
++};
++
++struct address_list {
++ int count;
++ char *addrs;
++ size_t size;
++ size_t len;
++};
++
+ #define DBC_ADD 1
+ #define DBC_DEL 2
+
+@@ -124,6 +137,37 @@
+ _exit(1);
+ }
+
++static int
++add_address(struct address_list *rec, struct listentry *addr)
++{
++ size_t entry_len = strlen(addr->entry);
++ size_t extra_len = (addr->af == AF_INET6) ? 6 : 5; /* semicolon, prefix and nul */
++ if (rec->len + entry_len + extra_len >= rec->size) {
++ char *tmp = reallocarray(rec->addrs, rec->size + 1024,
++ sizeof(char));
++ if (tmp == NULL) {
++ syslog_r(LOG_ERR, &sdata,
++ "configure_spamd: malloc failed");
++ return(-1);
++ }
++ rec->addrs = tmp;
++ if (rec->size == 0)
++ rec->addrs[0] = '\0';
++ rec->size += 1024;
++ }
++
++ strlcat(rec->addrs, ";", rec->size);
++ strlcat(rec->addrs, addr->entry, rec->size);
++ if (addr->af == AF_INET6)
++ strlcat(rec->addrs, "/128", rec->size);
++ else
++ strlcat(rec->addrs, "/32", rec->size);
++ rec->len += entry_len;
++ rec->count++;
++
++ return(0);
++}
++
+ /*
+ * Greatly simplified version from spamd_setup.c - only
+ * sends one blacklist to an already open stream. Has no need
+@@ -131,24 +175,36 @@
+ * host hits.
+ */
+ void
+-configure_spamd(char **addrs, u_int count, FILE *sdc)
++configure_spamd(struct listentry *addrs, u_int count, FILE *sdc)
+ {
+ u_int i;
++ struct address_list inet = { 0, NULL, 0, 0 };
++ struct address_list inet6 = { 0, NULL, 0, 0 };
+
+- /* XXX - doesn't support IPV6 yet */
+ fprintf(sdc, "%s;", traplist_name);
+ if (count != 0) {
+- fprintf(sdc, "%s;inet;%u", traplist_msg, count);
+- for (i = 0; i < count; i++)
+- fprintf(sdc, ";%s/32", addrs[i]);
++ for (i = 0; i < count; i++) {
++ if (addrs[i].af == AF_INET6)
++ (void)add_address(&inet6, &addrs[i]);
++ else
++ (void)add_address(&inet, &addrs[i]);
++ }
++
++ fprintf(sdc, "%s", traplist_msg);
++ if (inet.count > 0)
++ fprintf(sdc, ";inet;%u%s", inet.count, inet.addrs);
++ if (inet6.count > 0)
++ fprintf(sdc, ";inet6;%u%s", inet6.count, inet6.addrs);
+ }
++ free(inet.addrs);
++ free(inet6.addrs);
+ fputc('\n', sdc);
+ if (fflush(sdc) == EOF)
+ syslog_r(LOG_DEBUG, &sdata, "configure_spamd: fflush failed (%m)");
+ }
+
+ int
+-configure_pf(char **addrs, int count)
++configure_pf(struct listentry *addrs, int count)
+ {
+ FILE *pf = NULL;
+ int i, pdes[2], status;
+@@ -210,8 +266,9 @@
+ return(-1);
+ }
+ for (i = 0; i < count; i++)
+- if (addrs[i] != NULL)
+- fprintf(pf, "%s/32\n", addrs[i]);
++ if (addrs[i].entry != NULL)
++ fprintf(pf, "%s/%s\n", addrs[i].entry,
++ (addrs[i].af == AF_INET6) ? "128" : "32");
+ fclose(pf);
+
+ waitpid(pid, &status, 0);
+@@ -305,14 +362,14 @@
+
+ if (whitelist != NULL)
+ for (i = 0; i < whitecount; i++) {
+- free(whitelist[i]);
+- whitelist[i] = NULL;
++ free(whitelist[i].entry);
++ whitelist[i].entry = NULL;
+ }
+ whitecount = 0;
+ if (traplist != NULL) {
+ for (i = 0; i < trapcount; i++) {
+- free(traplist[i]);
+- traplist[i] = NULL;
++ free(traplist[i].entry);
++ traplist[i].entry = NULL;
+ }
+ }
+ trapcount = 0;
+@@ -325,17 +382,17 @@
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+- hints.ai_family = AF_INET; /*for now*/
++ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_protocol = IPPROTO_UDP; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(addr, NULL, &hints, &res) == 0) {
+ if (whitecount == whitealloc) {
+- char **tmp;
++ struct listentry *tmp;
+
+ tmp = reallocarray(whitelist,
+- whitealloc + 1024, sizeof(char *));
++ whitealloc + 1024, sizeof(struct listentry));
+ if (tmp == NULL) {
+ freeaddrinfo(res);
+ return(-1);
+@@ -343,11 +400,12 @@
+ whitelist = tmp;
+ whitealloc += 1024;
+ }
+- whitelist[whitecount] = strdup(addr);
+- if (whitelist[whitecount] == NULL) {
++ whitelist[whitecount].entry = strdup(addr);
++ if (whitelist[whitecount].entry == NULL) {
+ freeaddrinfo(res);
+ return(-1);
+ }
++ whitelist[whitecount].af = res->ai_family;
+ whitecount++;
+ freeaddrinfo(res);
+ } else
+@@ -362,17 +420,17 @@
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+- hints.ai_family = AF_INET; /*for now*/
++ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_protocol = IPPROTO_UDP; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(addr, NULL, &hints, &res) == 0) {
+ if (trapcount == trapalloc) {
+- char **tmp;
++ struct listentry *tmp;
+
+ tmp = reallocarray(traplist,
+- trapalloc + 1024, sizeof(char *));
++ trapalloc + 1024, sizeof(struct listentry));
+ if (tmp == NULL) {
+ freeaddrinfo(res);
+ return(-1);
+@@ -380,11 +438,12 @@
+ traplist = tmp;
+ trapalloc += 1024;
+ }
+- traplist[trapcount] = strdup(addr);
+- if (traplist[trapcount] == NULL) {
++ traplist[trapcount].entry = strdup(addr);
++ if (traplist[trapcount].entry == NULL) {
+ freeaddrinfo(res);
+ return(-1);
+ }
++ traplist[trapcount].af = res->ai_family;
+ trapcount++;
+ freeaddrinfo(res);
+ } else
+@@ -719,6 +778,7 @@
+ gd.bcount++;
+ } else
+ gd.pcount++;
++ gd.expire = expire;
+ memset(&dbk, 0, sizeof(dbk));
+ dbk.size = strlen(ip);
+ dbk.data = ip;
+@@ -880,13 +940,13 @@
+ int
+ twread(char *buf)
+ {
+- if ((strncmp(buf, "WHITE:", 6) == 0) ||
+- (strncmp(buf, "TRAP:", 5) == 0)) {
++ if ((strncmp(buf, "WHITE;", 6) == 0) ||
++ (strncmp(buf, "TRAP;", 5) == 0)) {
+ char **ap, *argv[5];
+ int argc = 0;
+
+ for (ap = argv;
+- ap < &argv[4] && (*ap = strsep(&buf, ":")) != NULL;) {
++ ap < &argv[4] && (*ap = strsep(&buf, ";")) != NULL;) {
+ if (**ap != '\0')
+ ap++;
+ argc++;
+@@ -910,7 +970,7 @@
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+- hints.ai_family = AF_INET; /*for now*/
++ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_protocol = IPPROTO_UDP; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+Index: spamd.c
+===================================================================
+RCS file: /cvs/src/libexec/spamd/spamd.c,v
+retrieving revision 1.137
+diff -u -r1.137 spamd.c
+--- spamd.c 12 Dec 2015 20:09:28 -0000 1.137
++++ spamd.c 31 Dec 2015 20:25:24 -0000
+@@ -56,8 +56,8 @@
+ int il;
+ struct sockaddr_storage ss;
+ void *ia;
+- char addr[32];
+- char caddr[32];
++ char addr[40];
++ char caddr[40];
+ char helo[MAX_MAIL], mail[MAX_MAIL], rcpt[MAX_MAIL];
+ struct sdlist **blacklists;
+ struct tls *cctx;
+@@ -113,6 +113,7 @@
+ int read_configline(FILE *);
+ void spamd_tls_init(void);
+ void check_spamd_db(void);
++void accept_connection(int, struct sockaddr *, socklen_t, struct con *);
+
+ char hostname[HOST_NAME_MAX+1];
+ struct syslog_data sdata = SYSLOG_DATA_INIT;
+@@ -709,9 +710,6 @@
+ time_t tt;
+ int error;
+
+- if (sa->sa_family != AF_INET)
+- errx(1, "not supported yet");
+-
+ time(&tt);
+ free(cp->obuf);
+ free(cp->blacklists);
+@@ -723,7 +721,10 @@
+ cp->pfd->fd = fd;
+ memcpy(&cp->ss, sa, sa->sa_len);
+ cp->af = sa->sa_family;
+- cp->ia = &((struct sockaddr_in *)&cp->ss)->sin_addr;
++ if (sa->sa_family == AF_INET)
++ cp->ia = &((struct sockaddr_in *)&cp->ss)->sin_addr;
++ else
++ cp->ia = &((struct sockaddr_in6 *)&cp->ss)->sin6_addr;
+ cp->blacklists = sdl_lookup(blacklists, cp->af, cp->ia);
+ cp->stutter = (greylist && !grey_stutter && cp->blacklists == NULL) ?
+ 0 : stutter;
+@@ -1208,13 +1209,54 @@
+ return(maxfiles - 200);
+ }
+
++void
++accept_connection(int sfd, struct sockaddr *sin,
++ socklen_t sinlen, struct con *con)
++{
++ int s2, i;
++
++ s2 = accept(sfd, sin, &sinlen);
++ if (s2 == -1) {
++ switch (errno) {
++ case EINTR:
++ case ECONNABORTED:
++ break;
++ case EMFILE:
++ case ENFILE:
++ slowdowntill = time(NULL) + 1;
++ break;
++ default:
++ errx(1, "accept");
++ }
++ } else {
++ /* Check if we hit the chosen fd limit */
++ for (i = 0; i < maxcon; i++)
++ if (con->pfd->fd == -1)
++ break;
++ if (i == maxcon) {
++ close(s2);
++ slowdowntill = 0;
++ } else {
++ initcon(&con[i], s2, sin);
++ syslog_r(LOG_INFO, &sdata,
++ "%s: connected (%d/%d)%s%s",
++ con[i].addr, clients, blackcount,
++ ((con[i].lists == NULL) ? "" :
++ ", lists:"),
++ ((con[i].lists == NULL) ? "":
++ con[i].lists));
++ }
++ }
++}
++
+ /* Symbolic indexes for pfd[] below */
+ #define PFD_SMTPLISTEN 0
+-#define PFD_CONFLISTEN 1
+-#define PFD_SYNCFD 2
+-#define PFD_CONFFD 3
+-#define PFD_TRAPFD 4
+-#define PFD_FIRSTCON 5
++#define PFD_SMTPLISTEN6 1
++#define PFD_CONFLISTEN 2
++#define PFD_SYNCFD 3
++#define PFD_CONFFD 4
++#define PFD_TRAPFD 5
++#define PFD_FIRSTCON 6
+
+ int
+ main(int argc, char *argv[])
+@@ -1222,15 +1264,24 @@
+ struct pollfd *pfd;
+ struct sockaddr_in sin;
+ struct sockaddr_in lin;
+- int ch, smtplisten, conflisten, syncfd = -1, i, one = 1;
++ struct sockaddr_in6 sin6;
++ int ch, smtplisten, smtplisten6, conflisten, syncfd = -1, i, one = 1;
+ u_short port;
+ long long passt, greyt, whitet;
+ struct servent *ent;
+ struct rlimit rlp;
+ char *bind_address = NULL;
++ char *bind6_address = NULL;
+ const char *errstr;
+ char *sync_iface = NULL;
+ char *sync_baddr = NULL;
++ struct addrinfo hints, *res;
++
++ memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_DGRAM; /* dummy */
++ hints.ai_protocol = IPPROTO_UDP; /* dummy */
++ hints.ai_flags = AI_NUMERICHOST;
+
+ tzset();
+ openlog_r("spamd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);
+@@ -1262,7 +1313,13 @@
+ nreply = "550";
+ break;
+ case 'l':
+- bind_address = optarg;
++ if (getaddrinfo(optarg, NULL, &hints, &res) != 0)
++ errx(1, "-l %s: invalid address", optarg);
++ if (res->ai_family == AF_INET6)
++ bind6_address = optarg;
++ else
++ bind_address = optarg;
++ freeaddrinfo(res);
+ break;
+ case 'B':
+ maxblack = strtonum(optarg, 0, INT_MAX, &errstr);
+@@ -1413,6 +1470,14 @@
+ sizeof(one)) == -1)
+ return (-1);
+
++ smtplisten6 = socket(AF_INET6, SOCK_STREAM, 0);
++ if (smtplisten6 == -1)
++ err(1, "socket");
++
++ if (setsockopt(smtplisten6, SOL_SOCKET, SO_REUSEADDR, &one,
++ sizeof(sin6)) == -1)
++ return (-1);
++
+ conflisten = socket(AF_INET, SOCK_STREAM, 0);
+ if (conflisten == -1)
+ err(1, "socket");
+@@ -1434,6 +1499,19 @@
+ if (bind(smtplisten, (struct sockaddr *)&sin, sizeof sin) == -1)
+ err(1, "bind");
+
++ memset(&sin6, 0, sizeof sin6);
++ sin6.sin6_len = sizeof(sin6);
++ if (bind6_address) {
++ if (inet_pton(AF_INET6, bind6_address, &sin6.sin6_addr) != 1)
++ err(1, "inet_pton");
++ } else
++ sin6.sin6_addr = (struct in6_addr)IN6ADDR_LOOPBACK_INIT;
++ sin6.sin6_family = AF_INET6;
++ sin6.sin6_port = htons(port);
++
++ if (bind(smtplisten6, (struct sockaddr *)&sin6, sizeof sin6) == -1)
++ err(1, "bind");
++
+ memset(&lin, 0, sizeof sin);
+ lin.sin_len = sizeof(sin);
+ lin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+@@ -1532,6 +1610,9 @@
+ if (listen(smtplisten, 10) == -1)
+ err(1, "listen");
+
++ if (listen(smtplisten6, 10) == -1)
++ err(1, "listen");
++
+ if (listen(conflisten, 10) == -1)
+ err(1, "listen");
+
+@@ -1557,6 +1638,7 @@
+
+ /* events and pfd entries for con[] are filled in below. */
+ pfd[PFD_SMTPLISTEN].fd = smtplisten;
++ pfd[PFD_SMTPLISTEN6].fd = smtplisten6;
+ pfd[PFD_CONFLISTEN].fd = conflisten;
+
+ while (1) {
+@@ -1595,11 +1677,13 @@
+ numcon = i + 1;
+ }
+ pfd[PFD_SMTPLISTEN].events = 0;
++ pfd[PFD_SMTPLISTEN6].events = 0;
+ pfd[PFD_CONFLISTEN].events = 0;
+ pfd[PFD_CONFFD].events = 0;
+ pfd[PFD_CONFFD].fd = conffd;
+ if (slowdowntill == 0) {
+ pfd[PFD_SMTPLISTEN].events = POLLIN;
++ pfd[PFD_SMTPLISTEN6].events = POLLIN;
+
+ /* only one active config conn at a time */
+ if (conffd == -1)
+@@ -1647,45 +1731,12 @@
+ handlew(&con[i], clients + 5 < maxcon);
+ }
+ }
+- if (pfd[PFD_SMTPLISTEN].revents & (POLLIN|POLLHUP)) {
+- socklen_t sinlen;
+- int s2;
+-
+- sinlen = sizeof(sin);
+- s2 = accept(smtplisten, (struct sockaddr *)&sin, &sinlen);
+- if (s2 == -1) {
+- switch (errno) {
+- case EINTR:
+- case ECONNABORTED:
+- break;
+- case EMFILE:
+- case ENFILE:
+- slowdowntill = time(NULL) + 1;
+- break;
+- default:
+- errx(1, "accept");
+- }
+- } else {
+- /* Check if we hit the chosen fd limit */
+- for (i = 0; i < maxcon; i++)
+- if (con[i].pfd->fd == -1)
+- break;
+- if (i == maxcon) {
+- close(s2);
+- slowdowntill = 0;
+- } else {
+- initcon(&con[i], s2,
+- (struct sockaddr *)&sin);
+- syslog_r(LOG_INFO, &sdata,
+- "%s: connected (%d/%d)%s%s",
+- con[i].addr, clients, blackcount,
+- ((con[i].lists == NULL) ? "" :
+- ", lists:"),
+- ((con[i].lists == NULL) ? "":
+- con[i].lists));
+- }
+- }
+- }
++ if (pfd[PFD_SMTPLISTEN].revents & (POLLIN|POLLHUP))
++ accept_connection(smtplisten, (struct sockaddr *)&sin,
++ sizeof(sin), con);
++ if (pfd[PFD_SMTPLISTEN6].revents & (POLLIN|POLLHUP))
++ accept_connection(smtplisten6, (struct sockaddr *)&sin6,
++ sizeof(sin6), con);
+ if (pfd[PFD_CONFLISTEN].revents & (POLLIN|POLLHUP)) {
+ socklen_t sinlen;
+
+Index: sync.c
+===================================================================
+RCS file: /cvs/src/libexec/spamd/sync.c,v
+retrieving revision 1.11
+diff -u -r1.11 sync.c
+--- sync.c 23 Nov 2014 21:19:47 -0000 1.11
++++ sync.c 31 Dec 2015 20:25:24 -0000
+@@ -241,11 +241,15 @@
+ struct sockaddr_in addr;
+ struct spam_synctlv_hdr *tlv;
+ struct spam_synctlv_grey *sg;
++ struct spam_synctlv_grey6 *sg6;
+ struct spam_synctlv_addr *sd;
++ struct spam_synctlv_addr6 *sd6;
+ u_int8_t buf[SPAM_SYNC_MAXSIZE];
+ u_int8_t hmac[2][SPAM_SYNC_HMAC_LEN];
+ struct in_addr ip;
++ struct in6_addr ip6;
+ char *from, *to, *helo;
++ char ipstr[40] = { '\0' };
+ u_int8_t *p;
+ socklen_t addr_len;
+ ssize_t len;
+@@ -268,7 +272,7 @@
+ hdr = (struct spam_synchdr *)buf;
+ if (len < sizeof(struct spam_synchdr) ||
+ hdr->sh_version != SPAM_SYNC_VERSION ||
+- hdr->sh_af != AF_INET ||
++ (hdr->sh_af != AF_INET && hdr->sh_af != AF_INET6) ||
+ len < ntohs(hdr->sh_length))
+ goto trunc;
+ len = ntohs(hdr->sh_length);
+@@ -296,72 +300,120 @@
+
+ switch (ntohs(tlv->st_type)) {
+ case SPAM_SYNC_GREY:
+- sg = (struct spam_synctlv_grey *)tlv;
+- if ((sizeof(*sg) +
+- ntohs(sg->sg_from_length) +
+- ntohs(sg->sg_to_length) +
+- ntohs(sg->sg_helo_length)) >
+- ntohs(tlv->st_length))
+- goto trunc;
+-
+- ip.s_addr = sg->sg_ip;
+- from = (char *)(sg + 1);
+- to = from + ntohs(sg->sg_from_length);
+- helo = to + ntohs(sg->sg_to_length);
++ if (hdr->sh_af == AF_INET) {
++ sg = (struct spam_synctlv_grey *)tlv;
++ if ((sizeof(*sg) +
++ ntohs(sg->sg_from_length) +
++ ntohs(sg->sg_to_length) +
++ ntohs(sg->sg_helo_length)) >
++ ntohs(tlv->st_length))
++ goto trunc;
++
++ ip.s_addr = sg->sg_ip;
++ inet_ntop(AF_INET, &ip, ipstr, sizeof(ipstr));
++
++ from = (char *)(sg + 1);
++ to = from + ntohs(sg->sg_from_length);
++ helo = to + ntohs(sg->sg_to_length);
++ } else {
++ sg6 = (struct spam_synctlv_grey6 *)tlv;
++ if ((sizeof(*sg6)) +
++ ntohs(sg6->sg6_from_length) +
++ ntohs(sg6->sg6_to_length) +
++ ntohs(sg6->sg6_helo_length) >
++ ntohs(tlv->st_length))
++ goto trunc;
++
++ memcpy(&ip6.s6_addr, &sg6->sg6_ip, sizeof(ip6.s6_addr));
++ inet_ntop(AF_INET6, &ip6, ipstr, sizeof(ipstr));
++
++ from = (char *)(sg6 + 1);
++ to = from + ntohs(sg6->sg6_from_length);
++ helo = to + ntohs(sg6->sg6_to_length);
++ }
++
+ if (debug) {
+ fprintf(stderr, "%s(sync): "
+ "received grey entry ",
+ inet_ntoa(addr.sin_addr));
+ fprintf(stderr, "helo %s ip %s "
+ "from %s to %s\n",
+- helo, inet_ntoa(ip), from, to);
++ helo, ipstr, from, to);
+ }
+ if (greylist) {
+ /* send this info to the greylister */
+ fprintf(grey,
+ "SYNC\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n",
+- helo, inet_ntoa(ip), from, to);
++ helo, ipstr, from, to);
+ fflush(grey);
+ }
+ break;
+ case SPAM_SYNC_WHITE:
+- sd = (struct spam_synctlv_addr *)tlv;
+- if (sizeof(*sd) != ntohs(tlv->st_length))
+- goto trunc;
++ if (hdr->sh_af == AF_INET) {
++ sd = (struct spam_synctlv_addr *)tlv;
++ if (sizeof(*sd) != ntohs(tlv->st_length))
++ goto trunc;
++
++ ip.s_addr = sd->sd_ip;
++ inet_ntop(AF_INET, &ip, ipstr, sizeof(ipstr));
++
++ expire = ntohl(sd->sd_expire);
++ } else {
++ sd6 = (struct spam_synctlv_addr6 *)tlv;
++ if (sizeof(*sd6) != ntohs(tlv->st_length))
++ goto trunc;
++
++ memcpy(&ip6.s6_addr, &sd6->sd6_ip, sizeof(ip6.s6_addr));
++ inet_ntop(AF_INET6, &ip6, ipstr, sizeof(ipstr));
++
++ expire = ntohl(sd6->sd6_expire);
++ }
+
+- ip.s_addr = sd->sd_ip;
+- expire = ntohl(sd->sd_expire);
+ if (debug) {
+ fprintf(stderr, "%s(sync): "
+ "received white entry ",
+ inet_ntoa(addr.sin_addr));
+- fprintf(stderr, "ip %s ", inet_ntoa(ip));
++ fprintf(stderr, "ip %s ", ipstr);
+ }
+ if (greylist) {
+ /* send this info to the greylister */
+- fprintf(grey, "WHITE:%s:", inet_ntoa(ip));
+- fprintf(grey, "%s:%u\n",
++ fprintf(grey, "WHITE;%s;", ipstr);
++ fprintf(grey, "%s;%u\n",
+ inet_ntoa(addr.sin_addr), expire);
+ fflush(grey);
+ }
+ break;
+ case SPAM_SYNC_TRAPPED:
+- sd = (struct spam_synctlv_addr *)tlv;
+- if (sizeof(*sd) != ntohs(tlv->st_length))
+- goto trunc;
++ if (hdr->sh_af == AF_INET) {
++ sd = (struct spam_synctlv_addr *)tlv;
++ if (sizeof(*sd) != ntohs(tlv->st_length))
++ goto trunc;
++
++ ip.s_addr = sd->sd_ip;
++ inet_ntop(AF_INET, &ip, ipstr, sizeof(ipstr));
++
++ expire = ntohl(sd->sd_expire);
++ } else {
++ sd6 = (struct spam_synctlv_addr6 *)tlv;
++ if (sizeof(*sd6) != ntohs(tlv->st_length))
++ goto trunc;
++
++ memcpy(&ip6.s6_addr, &sd6->sd6_ip, sizeof(ip6.s6_addr));
++ inet_ntop(AF_INET6, &ip6, ipstr, sizeof(ipstr));
++
++ expire = ntohl(sd6->sd6_expire);
++ }
+
+- ip.s_addr = sd->sd_ip;
+- expire = ntohl(sd->sd_expire);
+ if (debug) {
+ fprintf(stderr, "%s(sync): "
+ "received trapped entry ",
+ inet_ntoa(addr.sin_addr));
+- fprintf(stderr, "ip %s ", inet_ntoa(ip));
++ fprintf(stderr, "ip %s ", ipstr);
+ }
+ if (greylist) {
+ /* send this info to the greylister */
+- fprintf(grey, "TRAP:%s:", inet_ntoa(ip));
+- fprintf(grey, "%s:%u\n",
++ fprintf(grey, "TRAP;%s;", ipstr);
++ fprintf(grey, "%s;%u\n",
+ inet_ntoa(addr.sin_addr), expire);
+ fflush(grey);
+ }
+@@ -420,7 +472,10 @@
+ struct iovec iov[7];
+ struct spam_synchdr hdr;
+ struct spam_synctlv_grey sg;
++ struct spam_synctlv_grey6 sg6;
++
+ struct spam_synctlv_hdr end;
++ struct addrinfo hints, *res;
+ u_int16_t sglen, fromlen, tolen, helolen, padlen;
+ char pad[SPAM_ALIGNBYTES];
+ int i = 0;
+@@ -434,8 +489,20 @@
+
+ bzero(&hdr, sizeof(hdr));
+ bzero(&sg, sizeof(sg));
++ bzero(&sg6, sizeof(sg6));
+ bzero(&pad, sizeof(pad));
+
++ memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_DGRAM; /* dummy */
++ hints.ai_protocol = IPPROTO_UDP; /* dummy */
++ hints.ai_flags = AI_NUMERICHOST;
++
++ if (getaddrinfo(ip, NULL, &hints, &res) != 0) {
++ warnx("Invalid ip address: %s", ip);
++ return;
++ }
++
+ fromlen = strlen(from) + 1;
+ tolen = strlen(to) + 1;
+ helolen = strlen(helo) + 1;
+@@ -443,12 +510,15 @@
+ HMAC_CTX_init(&ctx);
+ HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1());
+
+- sglen = sizeof(sg) + fromlen + tolen + helolen;
++ if (res->ai_family == AF_INET)
++ sglen = sizeof(sg) + fromlen + tolen + helolen;
++ else
++ sglen = sizeof(sg6) + fromlen + tolen + helolen;
+ padlen = SPAM_ALIGN(sglen) - sglen;
+
+ /* Add SPAM sync packet header */
+ hdr.sh_version = SPAM_SYNC_VERSION;
+- hdr.sh_af = AF_INET;
++ hdr.sh_af = res->ai_family;
+ hdr.sh_counter = htonl(sync_counter++);
+ hdr.sh_length = htons(sizeof(hdr) + sglen + padlen + sizeof(end));
+ iov[i].iov_base = &hdr;
+@@ -456,16 +526,35 @@
+ HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len);
+ i++;
+
+- /* Add single SPAM sync greylisting entry */
+- sg.sg_type = htons(SPAM_SYNC_GREY);
+- sg.sg_length = htons(sglen + padlen);
+- sg.sg_timestamp = htonl(now);
+- sg.sg_ip = inet_addr(ip);
+- sg.sg_from_length = htons(fromlen);
+- sg.sg_to_length = htons(tolen);
+- sg.sg_helo_length = htons(helolen);
+- iov[i].iov_base = &sg;
+- iov[i].iov_len = sizeof(sg);
++ if (res->ai_family == AF_INET) {
++ /* Add single SPAM sync greylisting entry */
++ sg.sg_type = htons(SPAM_SYNC_GREY);
++ sg.sg_length = htons(sglen + padlen);
++ sg.sg_timestamp = htonl(now);
++
++ inet_pton(AF_INET, ip, &sg.sg_ip);
++
++ sg.sg_from_length = htons(fromlen);
++ sg.sg_to_length = htons(tolen);
++ sg.sg_helo_length = htons(helolen);
++ iov[i].iov_base = &sg;
++ iov[i].iov_len = sizeof(sg);
++ } else {
++ /* Add single SPAM sync greylisting entry */
++ sg6.sg6_type = htons(SPAM_SYNC_GREY);
++ sg6.sg6_length = htons(sglen + padlen);
++ sg6.sg6_timestamp = htonl(now);
++
++ inet_pton(AF_INET6, ip, &sg6.sg6_ip);
++
++ sg6.sg6_from_length = htons(fromlen);
++ sg6.sg6_to_length = htons(tolen);
++ sg6.sg6_helo_length = htons(helolen);
++ iov[i].iov_base = &sg6;
++ iov[i].iov_len = sizeof(sg6);
++ }
++ freeaddrinfo(res);
++
+ HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len);
+ i++;
+
+@@ -510,7 +599,9 @@
+ struct iovec iov[3];
+ struct spam_synchdr hdr;
+ struct spam_synctlv_addr sd;
++ struct spam_synctlv_addr6 sd6;
+ struct spam_synctlv_hdr end;
++ struct addrinfo hints, *res;
+ int i = 0;
+ HMAC_CTX ctx;
+ u_int hmac_len;
+@@ -521,28 +612,60 @@
+
+ bzero(&hdr, sizeof(hdr));
+ bzero(&sd, sizeof(sd));
++ bzero(&sd6, sizeof(sd6));
++
++ memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_DGRAM; /* dummy */
++ hints.ai_protocol = IPPROTO_UDP; /* dummy */
++ hints.ai_flags = AI_NUMERICHOST;
++
++ if (getaddrinfo(ip, NULL, &hints, &res) != 0) {
++ warnx("Invalid ip address: %s", ip);
++ return;
++ }
+
+ HMAC_CTX_init(&ctx);
+ HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1());
+
+ /* Add SPAM sync packet header */
+ hdr.sh_version = SPAM_SYNC_VERSION;
+- hdr.sh_af = AF_INET;
++ hdr.sh_af = res->ai_family;
+ hdr.sh_counter = htonl(sync_counter++);
+- hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end));
++ if (res->ai_family == AF_INET)
++ hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end));
++ else
++ hdr.sh_length = htons(sizeof(hdr) + sizeof(sd6) + sizeof(end));
+ iov[i].iov_base = &hdr;
+ iov[i].iov_len = sizeof(hdr);
+ HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len);
+ i++;
+
+- /* Add single SPAM sync address entry */
+- sd.sd_type = htons(type);
+- sd.sd_length = htons(sizeof(sd));
+- sd.sd_timestamp = htonl(now);
+- sd.sd_expire = htonl(expire);
+- sd.sd_ip = inet_addr(ip);
+- iov[i].iov_base = &sd;
+- iov[i].iov_len = sizeof(sd);
++ if (res->ai_family == AF_INET) {
++ /* Add single SPAM sync address entry */
++ sd.sd_type = htons(type);
++ sd.sd_length = htons(sizeof(sd));
++ sd.sd_timestamp = htonl(now);
++ sd.sd_expire = htonl(expire);
++
++ inet_pton(AF_INET, ip, &sd.sd_ip);
++
++ iov[i].iov_base = &sd;
++ iov[i].iov_len = sizeof(sd);
++ } else {
++ /* Add single SPAM sync address entry */
++ sd6.sd6_type = htons(type);
++ sd6.sd6_length = htons(sizeof(sd));
++ sd6.sd6_timestamp = htonl(now);
++ sd6.sd6_expire = htonl(expire);
++
++ inet_pton(AF_INET6, ip, &sd6.sd6_ip);
++
++ iov[i].iov_base = &sd6;
++ iov[i].iov_len = sizeof(sd6);
++ }
++ freeaddrinfo(res);
++
+ HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len);
+ i++;
+
+Index: sync.h
+===================================================================
+RCS file: /cvs/src/libexec/spamd/sync.h,v
+retrieving revision 1.3
+diff -u -r1.3 sync.h
+--- sync.h 22 May 2008 19:54:11 -0000 1.3
++++ sync.h 31 Dec 2015 20:25:24 -0000
+@@ -68,12 +68,31 @@
+ /* strings go here, then packet code re-aligns packet */
+ } __packed;
+
++struct spam_synctlv_grey6 {
++ u_int16_t sg6_type;
++ u_int16_t sg6_length;
++ u_int32_t sg6_timestamp;
++ u_int32_t sg6_ip[4];
++ u_int16_t sg6_from_length;
++ u_int16_t sg6_to_length;
++ u_int16_t sg6_helo_length;
++ /* strings go here, then packet code re-aligns packet */
++} __packed;
++
+ struct spam_synctlv_addr {
+ u_int16_t sd_type;
+ u_int16_t sd_length;
+ u_int32_t sd_timestamp;
+ u_int32_t sd_expire;
+ u_int32_t sd_ip;
++} __packed;
++
++struct spam_synctlv_addr6 {
++ u_int16_t sd6_type;
++ u_int16_t sd6_length;
++ u_int32_t sd6_timestamp;
++ u_int32_t sd6_expire;
++ u_int32_t sd6_ip[4];
+ } __packed;
+
+ #define SPAM_SYNC_END 0x0000