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