1*00ddf0caSbeck /* $OpenBSD: sync.c,v 1.8 2009/04/20 17:42:21 beck Exp $ */ 298babcadSbeck 398babcadSbeck /* 498babcadSbeck * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> 598babcadSbeck * 698babcadSbeck * Permission to use, copy, modify, and distribute this software for any 798babcadSbeck * purpose with or without fee is hereby granted, provided that the above 898babcadSbeck * copyright notice and this permission notice appear in all copies. 998babcadSbeck * 1098babcadSbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1198babcadSbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1298babcadSbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1398babcadSbeck * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1498babcadSbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1598babcadSbeck * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1698babcadSbeck * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1798babcadSbeck */ 1898babcadSbeck 1998babcadSbeck #include <sys/param.h> 2098babcadSbeck #include <sys/stdint.h> 2198babcadSbeck #include <sys/file.h> 2298babcadSbeck #include <sys/wait.h> 2398babcadSbeck #include <sys/socket.h> 2498babcadSbeck #include <sys/resource.h> 2598babcadSbeck #include <sys/uio.h> 2698babcadSbeck #include <sys/ioctl.h> 2798babcadSbeck #include <sys/queue.h> 2898babcadSbeck 2998babcadSbeck #include <net/if.h> 3098babcadSbeck #include <netinet/in.h> 3198babcadSbeck #include <arpa/inet.h> 3298babcadSbeck 3398babcadSbeck #include <err.h> 3498babcadSbeck #include <errno.h> 3598babcadSbeck #include <getopt.h> 3698babcadSbeck #include <pwd.h> 3798babcadSbeck #include <stdio.h> 3898babcadSbeck #include <stdlib.h> 3998babcadSbeck #include <string.h> 4098babcadSbeck #include <unistd.h> 4198babcadSbeck #include <sha1.h> 4298babcadSbeck #include <syslog.h> 4398babcadSbeck 4498babcadSbeck #include <netdb.h> 4598babcadSbeck 4698babcadSbeck #include <openssl/hmac.h> 4798babcadSbeck 4898babcadSbeck #include "sdl.h" 4998babcadSbeck #include "grey.h" 5098babcadSbeck #include "sync.h" 5198babcadSbeck 5298babcadSbeck extern struct syslog_data sdata; 5398babcadSbeck extern int debug; 5498babcadSbeck extern FILE *grey; 5598babcadSbeck extern int greylist; 5698babcadSbeck 5798babcadSbeck u_int32_t sync_counter; 5898babcadSbeck int syncfd; 5998babcadSbeck int sendmcast; 6098babcadSbeck struct sockaddr_in sync_in; 6198babcadSbeck struct sockaddr_in sync_out; 6298babcadSbeck static char *sync_key; 6398babcadSbeck 6498babcadSbeck struct sync_host { 6598babcadSbeck LIST_ENTRY(sync_host) h_entry; 6698babcadSbeck 6798babcadSbeck char *h_name; 68f6c3b21dSotto struct sockaddr_in sh_addr; 6998babcadSbeck }; 7098babcadSbeck LIST_HEAD(synchosts, sync_host) sync_hosts = LIST_HEAD_INITIALIZER(sync_hosts); 7198babcadSbeck 7298babcadSbeck void sync_send(struct iovec *, int); 7398babcadSbeck void sync_addr(time_t, time_t, char *, u_int16_t); 7498babcadSbeck 7598babcadSbeck int 7698babcadSbeck sync_addhost(const char *name, u_short port) 7798babcadSbeck { 7898babcadSbeck struct addrinfo hints, *res, *res0; 7998babcadSbeck struct sync_host *shost; 8098babcadSbeck struct sockaddr_in *addr = NULL; 8198babcadSbeck 8298babcadSbeck bzero(&hints, sizeof(hints)); 8398babcadSbeck hints.ai_family = PF_UNSPEC; 8498babcadSbeck hints.ai_socktype = SOCK_STREAM; 8598babcadSbeck if (getaddrinfo(name, NULL, &hints, &res0) != 0) 8698babcadSbeck return (EINVAL); 8798babcadSbeck for (res = res0; res != NULL; res = res->ai_next) { 8898babcadSbeck if (addr == NULL && res->ai_family == AF_INET) { 8998babcadSbeck addr = (struct sockaddr_in *)res->ai_addr; 9098babcadSbeck break; 9198babcadSbeck } 9298babcadSbeck } 9398babcadSbeck if (addr == NULL) { 9498babcadSbeck freeaddrinfo(res0); 9598babcadSbeck return (EINVAL); 9698babcadSbeck } 9798babcadSbeck if ((shost = (struct sync_host *) 9898babcadSbeck calloc(1, sizeof(struct sync_host))) == NULL) { 9998babcadSbeck freeaddrinfo(res0); 10098babcadSbeck return (ENOMEM); 10198babcadSbeck } 10298babcadSbeck if ((shost->h_name = strdup(name)) == NULL) { 10398babcadSbeck free(shost); 10498babcadSbeck freeaddrinfo(res0); 10598babcadSbeck return (ENOMEM); 10698babcadSbeck } 10798babcadSbeck 108f6c3b21dSotto shost->sh_addr.sin_family = AF_INET; 109f6c3b21dSotto shost->sh_addr.sin_port = htons(port); 110f6c3b21dSotto shost->sh_addr.sin_addr.s_addr = addr->sin_addr.s_addr; 11198babcadSbeck freeaddrinfo(res0); 11298babcadSbeck 11398babcadSbeck LIST_INSERT_HEAD(&sync_hosts, shost, h_entry); 11498babcadSbeck 11598babcadSbeck if (debug) 11698babcadSbeck fprintf(stderr, "added spam sync host %s " 11798babcadSbeck "(address %s, port %d)\n", shost->h_name, 118f6c3b21dSotto inet_ntoa(shost->sh_addr.sin_addr), port); 11998babcadSbeck 12098babcadSbeck return (0); 12198babcadSbeck } 12298babcadSbeck 12398babcadSbeck int 12498babcadSbeck sync_init(const char *iface, const char *baddr, u_short port) 12598babcadSbeck { 12698babcadSbeck int one = 1; 12798babcadSbeck u_int8_t ttl; 12898babcadSbeck struct ifreq ifr; 12998babcadSbeck struct ip_mreq mreq; 13098babcadSbeck struct sockaddr_in *addr; 13198babcadSbeck char ifnam[IFNAMSIZ], *ttlstr; 13298babcadSbeck const char *errstr; 13398babcadSbeck struct in_addr ina; 13498babcadSbeck 13598babcadSbeck if (iface != NULL) 13698babcadSbeck sendmcast++; 13798babcadSbeck 13898babcadSbeck bzero(&ina, sizeof(ina)); 13998babcadSbeck if (baddr != NULL) { 14098babcadSbeck if (inet_pton(AF_INET, baddr, &ina) != 1) { 14198babcadSbeck ina.s_addr = htonl(INADDR_ANY); 14298babcadSbeck if (iface == NULL) 14398babcadSbeck iface = baddr; 14498babcadSbeck else if (iface != NULL && strcmp(baddr, iface) != 0) { 14598babcadSbeck fprintf(stderr, "multicast interface does " 14698babcadSbeck "not match"); 14798babcadSbeck return (-1); 14898babcadSbeck } 14998babcadSbeck } 15098babcadSbeck } 15198babcadSbeck 15298babcadSbeck sync_key = SHA1File(SPAM_SYNC_KEY, NULL); 15398babcadSbeck if (sync_key == NULL) { 15498babcadSbeck if (errno != ENOENT) { 15598babcadSbeck fprintf(stderr, "failed to open sync key: %s\n", 15698babcadSbeck strerror(errno)); 15798babcadSbeck return (-1); 15898babcadSbeck } 15998babcadSbeck /* Use empty key by default */ 16098babcadSbeck sync_key = ""; 16198babcadSbeck } 16298babcadSbeck 16398babcadSbeck syncfd = socket(AF_INET, SOCK_DGRAM, 0); 16498babcadSbeck if (syncfd == -1) 16598babcadSbeck return (-1); 16698babcadSbeck 16798babcadSbeck if (setsockopt(syncfd, SOL_SOCKET, SO_REUSEADDR, &one, 16898babcadSbeck sizeof(one)) == -1) 16998babcadSbeck goto fail; 17098babcadSbeck 17198babcadSbeck bzero(&sync_out, sizeof(sync_out)); 17298babcadSbeck sync_out.sin_family = AF_INET; 17398babcadSbeck sync_out.sin_len = sizeof(sync_out); 17498babcadSbeck sync_out.sin_addr.s_addr = ina.s_addr; 17598babcadSbeck if (baddr == NULL && iface == NULL) 17698babcadSbeck sync_out.sin_port = 0; 17798babcadSbeck else 17898babcadSbeck sync_out.sin_port = htons(port); 17998babcadSbeck 18098babcadSbeck if (bind(syncfd, (struct sockaddr *)&sync_out, sizeof(sync_out)) == -1) 18198babcadSbeck goto fail; 18298babcadSbeck 18398babcadSbeck /* Don't use multicast messages */ 18498babcadSbeck if (iface == NULL) 18598babcadSbeck return (syncfd); 18698babcadSbeck 18798babcadSbeck strlcpy(ifnam, iface, sizeof(ifnam)); 18898babcadSbeck ttl = SPAM_SYNC_MCASTTTL; 18998babcadSbeck if ((ttlstr = strchr(ifnam, ':')) != NULL) { 19098babcadSbeck *ttlstr++ = '\0'; 19198babcadSbeck ttl = (u_int8_t)strtonum(ttlstr, 1, UINT8_MAX, &errstr); 19298babcadSbeck if (errstr) { 19398babcadSbeck fprintf(stderr, "invalid multicast ttl %s: %s", 19498babcadSbeck ttlstr, errstr); 19598babcadSbeck goto fail; 19698babcadSbeck } 19798babcadSbeck } 19898babcadSbeck 19998babcadSbeck bzero(&ifr, sizeof(ifr)); 20098babcadSbeck strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); 20198babcadSbeck if (ioctl(syncfd, SIOCGIFADDR, &ifr) == -1) 20298babcadSbeck goto fail; 20398babcadSbeck 20498babcadSbeck bzero(&sync_in, sizeof(sync_in)); 20598babcadSbeck addr = (struct sockaddr_in *)&ifr.ifr_addr; 20698babcadSbeck sync_in.sin_family = AF_INET; 20798babcadSbeck sync_in.sin_len = sizeof(sync_in); 20898babcadSbeck sync_in.sin_addr.s_addr = addr->sin_addr.s_addr; 20998babcadSbeck sync_in.sin_port = htons(port); 21098babcadSbeck 21198babcadSbeck bzero(&mreq, sizeof(mreq)); 21298babcadSbeck sync_out.sin_addr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR); 21398babcadSbeck mreq.imr_multiaddr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR); 21498babcadSbeck mreq.imr_interface.s_addr = sync_in.sin_addr.s_addr; 21598babcadSbeck 21698babcadSbeck if (setsockopt(syncfd, IPPROTO_IP, 21798babcadSbeck IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { 21898babcadSbeck fprintf(stderr, "failed to add multicast membership to %s: %s", 21998babcadSbeck SPAM_SYNC_MCASTADDR, strerror(errno)); 22098babcadSbeck goto fail; 22198babcadSbeck } 22298babcadSbeck if (setsockopt(syncfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 22398babcadSbeck sizeof(ttl)) < 0) { 22498babcadSbeck fprintf(stderr, "failed to set multicast ttl to " 22598babcadSbeck "%u: %s\n", ttl, strerror(errno)); 22698babcadSbeck setsockopt(syncfd, IPPROTO_IP, 22798babcadSbeck IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); 22898babcadSbeck goto fail; 22998babcadSbeck } 23098babcadSbeck 23198babcadSbeck if (debug) 23298babcadSbeck printf("using multicast spam sync %smode " 23398babcadSbeck "(ttl %u, group %s, port %d)\n", 23498babcadSbeck sendmcast ? "" : "receive ", 23598babcadSbeck ttl, inet_ntoa(sync_out.sin_addr), port); 23698babcadSbeck 23798babcadSbeck return (syncfd); 23898babcadSbeck 23998babcadSbeck fail: 24098babcadSbeck close(syncfd); 24198babcadSbeck return (-1); 24298babcadSbeck } 24398babcadSbeck 24498babcadSbeck void 24598babcadSbeck sync_recv(void) 24698babcadSbeck { 24798babcadSbeck struct spam_synchdr *hdr; 24898babcadSbeck struct sockaddr_in addr; 24998babcadSbeck struct spam_synctlv_hdr *tlv; 25098babcadSbeck struct spam_synctlv_grey *sg; 25198babcadSbeck struct spam_synctlv_addr *sd; 25298babcadSbeck u_int8_t buf[SPAM_SYNC_MAXSIZE]; 25398babcadSbeck u_int8_t hmac[2][SPAM_SYNC_HMAC_LEN]; 25498babcadSbeck struct in_addr ip; 25598babcadSbeck char *from, *to, *helo; 25698babcadSbeck u_int8_t *p; 25798babcadSbeck socklen_t addr_len; 25898babcadSbeck ssize_t len; 25998babcadSbeck u_int hmac_len; 26098babcadSbeck time_t expire; 26198babcadSbeck 26298babcadSbeck bzero(&addr, sizeof(addr)); 26398babcadSbeck bzero(buf, sizeof(buf)); 26498babcadSbeck 26598babcadSbeck addr_len = sizeof(addr); 26698babcadSbeck if ((len = recvfrom(syncfd, buf, sizeof(buf), 0, 26798babcadSbeck (struct sockaddr *)&addr, &addr_len)) < 1) 26898babcadSbeck return; 26998babcadSbeck if (addr.sin_addr.s_addr != htonl(INADDR_ANY) && 27098babcadSbeck bcmp(&sync_in.sin_addr, &addr.sin_addr, 27198babcadSbeck sizeof(addr.sin_addr)) == 0) 27298babcadSbeck return; 27398babcadSbeck 27498babcadSbeck /* Ignore invalid or truncated packets */ 27598babcadSbeck hdr = (struct spam_synchdr *)buf; 276544df9d5Sreyk if (len < sizeof(struct spam_synchdr) || 277544df9d5Sreyk hdr->sh_version != SPAM_SYNC_VERSION || 27898babcadSbeck hdr->sh_af != AF_INET || 27998babcadSbeck len < ntohs(hdr->sh_length)) 28098babcadSbeck goto trunc; 28198babcadSbeck len = ntohs(hdr->sh_length); 28298babcadSbeck 28398babcadSbeck /* Compute and validate HMAC */ 28498babcadSbeck bcopy(hdr->sh_hmac, hmac[0], SPAM_SYNC_HMAC_LEN); 28598babcadSbeck bzero(hdr->sh_hmac, SPAM_SYNC_HMAC_LEN); 28698babcadSbeck HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len, 28798babcadSbeck hmac[1], &hmac_len); 28898babcadSbeck if (bcmp(hmac[0], hmac[1], SPAM_SYNC_HMAC_LEN) != 0) 28998babcadSbeck goto trunc; 29098babcadSbeck 29198babcadSbeck if (debug) 29298babcadSbeck fprintf(stderr, 29398babcadSbeck "%s(sync): received packet of %d bytes\n", 29498babcadSbeck inet_ntoa(addr.sin_addr), (int)len); 29598babcadSbeck 29698babcadSbeck p = (u_int8_t *)(hdr + 1); 29798babcadSbeck while (len) { 29898babcadSbeck tlv = (struct spam_synctlv_hdr *)p; 29998babcadSbeck 300fcca1eedSreyk if (len < sizeof(struct spam_synctlv_hdr) || 301fcca1eedSreyk len < ntohs(tlv->st_length)) 30298babcadSbeck goto trunc; 30398babcadSbeck 30498babcadSbeck switch (ntohs(tlv->st_type)) { 30598babcadSbeck case SPAM_SYNC_GREY: 30698babcadSbeck sg = (struct spam_synctlv_grey *)tlv; 30798babcadSbeck if ((sizeof(*sg) + 30898babcadSbeck ntohs(sg->sg_from_length) + 30998babcadSbeck ntohs(sg->sg_to_length) + 31098babcadSbeck ntohs(sg->sg_helo_length)) > 31198babcadSbeck ntohs(tlv->st_length)) 31298babcadSbeck goto trunc; 31398babcadSbeck 314d72b910dSderaadt ip.s_addr = sg->sg_ip; 31598babcadSbeck from = (char *)(sg + 1); 31698babcadSbeck to = from + ntohs(sg->sg_from_length); 31798babcadSbeck helo = to + ntohs(sg->sg_to_length); 31898babcadSbeck if (debug) { 31998babcadSbeck fprintf(stderr, "%s(sync): " 32098babcadSbeck "received grey entry ", 32198babcadSbeck inet_ntoa(addr.sin_addr)); 32298babcadSbeck fprintf(stderr, "helo %s ip %s " 32398babcadSbeck "from %s to %s\n", 32498babcadSbeck helo, inet_ntoa(ip), from, to); 32598babcadSbeck } 32698babcadSbeck if (greylist) { 32798babcadSbeck /* send this info to the greylister */ 32898babcadSbeck fprintf(grey, 32998babcadSbeck "SYNC\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n", 33098babcadSbeck helo, inet_ntoa(ip), from, to); 33198babcadSbeck fflush(grey); 33298babcadSbeck } 33398babcadSbeck break; 33498babcadSbeck case SPAM_SYNC_WHITE: 33598babcadSbeck sd = (struct spam_synctlv_addr *)tlv; 33698babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length)) 33798babcadSbeck goto trunc; 33898babcadSbeck 339d72b910dSderaadt ip.s_addr = sd->sd_ip; 34098babcadSbeck expire = ntohl(sd->sd_expire); 34198babcadSbeck if (debug) { 34298babcadSbeck fprintf(stderr, "%s(sync): " 34398babcadSbeck "received white entry ", 34498babcadSbeck inet_ntoa(addr.sin_addr)); 34598babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip)); 34698babcadSbeck } 34798babcadSbeck if (greylist) { 34898babcadSbeck /* send this info to the greylister */ 34998babcadSbeck fprintf(grey, "WHITE:%s:", inet_ntoa(ip)); 35098babcadSbeck fprintf(grey, "%s:%u\n", 35198babcadSbeck inet_ntoa(addr.sin_addr), expire); 35298babcadSbeck fflush(grey); 35398babcadSbeck } 35498babcadSbeck break; 35598babcadSbeck case SPAM_SYNC_TRAPPED: 35698babcadSbeck sd = (struct spam_synctlv_addr *)tlv; 35798babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length)) 35898babcadSbeck goto trunc; 35998babcadSbeck 360d72b910dSderaadt ip.s_addr = sd->sd_ip; 36198babcadSbeck expire = ntohl(sd->sd_expire); 36298babcadSbeck if (debug) { 36398babcadSbeck fprintf(stderr, "%s(sync): " 36498babcadSbeck "received trapped entry ", 36598babcadSbeck inet_ntoa(addr.sin_addr)); 36698babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip)); 36798babcadSbeck } 36898babcadSbeck if (greylist) { 36998babcadSbeck /* send this info to the greylister */ 37098babcadSbeck fprintf(grey, "TRAP:%s:", inet_ntoa(ip)); 37198babcadSbeck fprintf(grey, "%s:%u\n", 37298babcadSbeck inet_ntoa(addr.sin_addr), expire); 37398babcadSbeck fflush(grey); 37498babcadSbeck } 37598babcadSbeck break; 37698babcadSbeck case SPAM_SYNC_END: 37798babcadSbeck goto done; 37898babcadSbeck default: 37998babcadSbeck printf("invalid type: %d\n", ntohs(tlv->st_type)); 38098babcadSbeck goto trunc; 38198babcadSbeck } 38298babcadSbeck len -= ntohs(tlv->st_length); 38398babcadSbeck p = ((u_int8_t *)tlv) + ntohs(tlv->st_length); 38498babcadSbeck } 38598babcadSbeck 38698babcadSbeck done: 38798babcadSbeck return; 38898babcadSbeck 38998babcadSbeck trunc: 39098babcadSbeck if (debug) 39198babcadSbeck fprintf(stderr, "%s(sync): truncated or invalid packet\n", 39298babcadSbeck inet_ntoa(addr.sin_addr)); 39398babcadSbeck } 39498babcadSbeck 39598babcadSbeck void 39698babcadSbeck sync_send(struct iovec *iov, int iovlen) 39798babcadSbeck { 39898babcadSbeck struct sync_host *shost; 39998babcadSbeck struct msghdr msg; 40098babcadSbeck 40198babcadSbeck /* setup buffer */ 40298babcadSbeck bzero(&msg, sizeof(msg)); 40398babcadSbeck msg.msg_iov = iov; 40498babcadSbeck msg.msg_iovlen = iovlen; 40598babcadSbeck 40698babcadSbeck if (sendmcast) { 40798babcadSbeck if (debug) 40898babcadSbeck fprintf(stderr, "sending multicast sync message\n"); 40998babcadSbeck msg.msg_name = &sync_out; 41098babcadSbeck msg.msg_namelen = sizeof(sync_out); 41198babcadSbeck sendmsg(syncfd, &msg, 0); 41298babcadSbeck } 41398babcadSbeck 41498babcadSbeck LIST_FOREACH(shost, &sync_hosts, h_entry) { 41598babcadSbeck if (debug) 41698babcadSbeck fprintf(stderr, "sending sync message to %s (%s)\n", 417f6c3b21dSotto shost->h_name, inet_ntoa(shost->sh_addr.sin_addr)); 418f6c3b21dSotto msg.msg_name = &shost->sh_addr; 419f6c3b21dSotto msg.msg_namelen = sizeof(shost->sh_addr); 42098babcadSbeck sendmsg(syncfd, &msg, 0); 42198babcadSbeck } 42298babcadSbeck } 42398babcadSbeck 42498babcadSbeck void 42598babcadSbeck sync_update(time_t now, char *helo, char *ip, char *from, char *to) 42698babcadSbeck { 4274aba4ff9Sderaadt struct iovec iov[7]; 42898babcadSbeck struct spam_synchdr hdr; 42998babcadSbeck struct spam_synctlv_grey sg; 43098babcadSbeck struct spam_synctlv_hdr end; 4314aba4ff9Sderaadt u_int16_t sglen, fromlen, tolen, helolen, padlen; 4324aba4ff9Sderaadt char pad[SPAM_ALIGNBYTES]; 43398babcadSbeck int i = 0; 43498babcadSbeck HMAC_CTX ctx; 43598babcadSbeck u_int hmac_len; 43698babcadSbeck 43798babcadSbeck if (debug) 43898babcadSbeck fprintf(stderr, 43998babcadSbeck "sync grey update helo %s ip %s from %s to %s\n", 44098babcadSbeck helo, ip, from, to); 44198babcadSbeck 44298babcadSbeck bzero(&hdr, sizeof(hdr)); 44398babcadSbeck bzero(&sg, sizeof(sg)); 4444aba4ff9Sderaadt bzero(&pad, sizeof(pad)); 44598babcadSbeck 44698babcadSbeck fromlen = strlen(from) + 1; 44798babcadSbeck tolen = strlen(to) + 1; 44898babcadSbeck helolen = strlen(helo) + 1; 44998babcadSbeck 45098babcadSbeck HMAC_CTX_init(&ctx); 45198babcadSbeck HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); 45298babcadSbeck 4534aba4ff9Sderaadt sglen = sizeof(sg) + fromlen + tolen + helolen; 4544aba4ff9Sderaadt padlen = SPAM_ALIGN(sglen) - sglen; 4554aba4ff9Sderaadt 45698babcadSbeck /* Add SPAM sync packet header */ 45798babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION; 45898babcadSbeck hdr.sh_af = AF_INET; 459d72b910dSderaadt hdr.sh_counter = htonl(sync_counter++); 4604aba4ff9Sderaadt hdr.sh_length = htons(sizeof(hdr) + sglen + padlen + sizeof(end)); 46198babcadSbeck iov[i].iov_base = &hdr; 46298babcadSbeck iov[i].iov_len = sizeof(hdr); 46398babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 46498babcadSbeck i++; 46598babcadSbeck 46698babcadSbeck /* Add single SPAM sync greylisting entry */ 46798babcadSbeck sg.sg_type = htons(SPAM_SYNC_GREY); 4684aba4ff9Sderaadt sg.sg_length = htons(sglen + padlen); 46998babcadSbeck sg.sg_timestamp = htonl(now); 470d72b910dSderaadt sg.sg_ip = inet_addr(ip); 47198babcadSbeck sg.sg_from_length = htons(fromlen); 47298babcadSbeck sg.sg_to_length = htons(tolen); 47398babcadSbeck sg.sg_helo_length = htons(helolen); 47498babcadSbeck iov[i].iov_base = &sg; 47598babcadSbeck iov[i].iov_len = sizeof(sg); 47698babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 47798babcadSbeck i++; 47898babcadSbeck 47998babcadSbeck iov[i].iov_base = from; 48098babcadSbeck iov[i].iov_len = fromlen; 48198babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 48298babcadSbeck i++; 48398babcadSbeck 48498babcadSbeck iov[i].iov_base = to; 48598babcadSbeck iov[i].iov_len = tolen; 48698babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 48798babcadSbeck i++; 48898babcadSbeck 48998babcadSbeck iov[i].iov_base = helo; 49098babcadSbeck iov[i].iov_len = helolen; 49198babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 49298babcadSbeck i++; 49398babcadSbeck 4944aba4ff9Sderaadt iov[i].iov_base = pad; 4954aba4ff9Sderaadt iov[i].iov_len = padlen; 4964aba4ff9Sderaadt HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 4974aba4ff9Sderaadt i++; 4984aba4ff9Sderaadt 49998babcadSbeck /* Add end marker */ 50098babcadSbeck end.st_type = htons(SPAM_SYNC_END); 50198babcadSbeck end.st_length = htons(sizeof(end)); 50298babcadSbeck iov[i].iov_base = &end; 50398babcadSbeck iov[i].iov_len = sizeof(end); 50498babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 50598babcadSbeck i++; 50698babcadSbeck 50798babcadSbeck HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); 50898babcadSbeck 50998babcadSbeck /* Send message to the target hosts */ 51098babcadSbeck sync_send(iov, i); 5111d936ddfSbeck HMAC_CTX_cleanup(&ctx); 51298babcadSbeck } 51398babcadSbeck 51498babcadSbeck void 51598babcadSbeck sync_addr(time_t now, time_t expire, char *ip, u_int16_t type) 51698babcadSbeck { 51798babcadSbeck struct iovec iov[3]; 51898babcadSbeck struct spam_synchdr hdr; 51998babcadSbeck struct spam_synctlv_addr sd; 52098babcadSbeck struct spam_synctlv_hdr end; 52198babcadSbeck int i = 0; 52298babcadSbeck HMAC_CTX ctx; 52398babcadSbeck u_int hmac_len; 52498babcadSbeck 52598babcadSbeck if (debug) 526*00ddf0caSbeck fprintf(stderr, "sync %s %s\n", 527*00ddf0caSbeck type == SPAM_SYNC_WHITE ? "white" : "trapped", ip); 52898babcadSbeck 52998babcadSbeck bzero(&hdr, sizeof(hdr)); 53098babcadSbeck bzero(&sd, sizeof(sd)); 53198babcadSbeck 53298babcadSbeck HMAC_CTX_init(&ctx); 53398babcadSbeck HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); 53498babcadSbeck 53598babcadSbeck /* Add SPAM sync packet header */ 53698babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION; 53798babcadSbeck hdr.sh_af = AF_INET; 538d72b910dSderaadt hdr.sh_counter = htonl(sync_counter++); 53998babcadSbeck hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end)); 54098babcadSbeck iov[i].iov_base = &hdr; 54198babcadSbeck iov[i].iov_len = sizeof(hdr); 54298babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 54398babcadSbeck i++; 54498babcadSbeck 54598babcadSbeck /* Add single SPAM sync address entry */ 54698babcadSbeck sd.sd_type = htons(type); 54798babcadSbeck sd.sd_length = htons(sizeof(sd)); 54898babcadSbeck sd.sd_timestamp = htonl(now); 54998babcadSbeck sd.sd_expire = htonl(expire); 550d72b910dSderaadt sd.sd_ip = inet_addr(ip); 55198babcadSbeck iov[i].iov_base = &sd; 55298babcadSbeck iov[i].iov_len = sizeof(sd); 55398babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 55498babcadSbeck i++; 55598babcadSbeck 55698babcadSbeck /* Add end marker */ 55798babcadSbeck end.st_type = htons(SPAM_SYNC_END); 55898babcadSbeck end.st_length = htons(sizeof(end)); 55998babcadSbeck iov[i].iov_base = &end; 56098babcadSbeck iov[i].iov_len = sizeof(end); 56198babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 56298babcadSbeck i++; 56398babcadSbeck 56498babcadSbeck HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); 56598babcadSbeck 56698babcadSbeck /* Send message to the target hosts */ 56798babcadSbeck sync_send(iov, i); 5681d936ddfSbeck HMAC_CTX_cleanup(&ctx); 56998babcadSbeck } 57098babcadSbeck 57198babcadSbeck void 57298babcadSbeck sync_white(time_t now, time_t expire, char *ip) 57398babcadSbeck { 57498babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_WHITE); 57598babcadSbeck } 57698babcadSbeck 57798babcadSbeck void 57898babcadSbeck sync_trapped(time_t now, time_t expire, char *ip) 57998babcadSbeck { 58098babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_TRAPPED); 58198babcadSbeck } 582