1*f6c3b21dSotto /* $OpenBSD: sync.c,v 1.3 2007/04/13 05:55:03 otto 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; 68*f6c3b21dSotto 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 108*f6c3b21dSotto shost->sh_addr.sin_family = AF_INET; 109*f6c3b21dSotto shost->sh_addr.sin_port = htons(port); 110*f6c3b21dSotto 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, 118*f6c3b21dSotto 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; 27698babcadSbeck if (hdr->sh_version != SPAM_SYNC_VERSION || 27798babcadSbeck hdr->sh_af != AF_INET || 27898babcadSbeck len < ntohs(hdr->sh_length)) 27998babcadSbeck goto trunc; 28098babcadSbeck len = ntohs(hdr->sh_length); 28198babcadSbeck 28298babcadSbeck /* Compute and validate HMAC */ 28398babcadSbeck bcopy(hdr->sh_hmac, hmac[0], SPAM_SYNC_HMAC_LEN); 28498babcadSbeck bzero(hdr->sh_hmac, SPAM_SYNC_HMAC_LEN); 28598babcadSbeck HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len, 28698babcadSbeck hmac[1], &hmac_len); 28798babcadSbeck if (bcmp(hmac[0], hmac[1], SPAM_SYNC_HMAC_LEN) != 0) 28898babcadSbeck goto trunc; 28998babcadSbeck 29098babcadSbeck if (debug) 29198babcadSbeck fprintf(stderr, 29298babcadSbeck "%s(sync): received packet of %d bytes\n", 29398babcadSbeck inet_ntoa(addr.sin_addr), (int)len); 29498babcadSbeck 29598babcadSbeck p = (u_int8_t *)(hdr + 1); 29698babcadSbeck while (len) { 29798babcadSbeck tlv = (struct spam_synctlv_hdr *)p; 29898babcadSbeck 29998babcadSbeck if (len < ntohs(tlv->st_length)) 30098babcadSbeck goto trunc; 30198babcadSbeck 30298babcadSbeck switch (ntohs(tlv->st_type)) { 30398babcadSbeck case SPAM_SYNC_GREY: 30498babcadSbeck sg = (struct spam_synctlv_grey *)tlv; 30598babcadSbeck if ((sizeof(*sg) + 30698babcadSbeck ntohs(sg->sg_from_length) + 30798babcadSbeck ntohs(sg->sg_to_length) + 30898babcadSbeck ntohs(sg->sg_helo_length)) > 30998babcadSbeck ntohs(tlv->st_length)) 31098babcadSbeck goto trunc; 31198babcadSbeck 31298babcadSbeck ip.s_addr = (u_int32_t)ntohl(sg->sg_ip); 31398babcadSbeck from = (char *)(sg + 1); 31498babcadSbeck to = from + ntohs(sg->sg_from_length); 31598babcadSbeck helo = to + ntohs(sg->sg_to_length); 31698babcadSbeck if (debug) { 31798babcadSbeck fprintf(stderr, "%s(sync): " 31898babcadSbeck "received grey entry ", 31998babcadSbeck inet_ntoa(addr.sin_addr)); 32098babcadSbeck fprintf(stderr, "helo %s ip %s " 32198babcadSbeck "from %s to %s\n", 32298babcadSbeck helo, inet_ntoa(ip), from, to); 32398babcadSbeck } 32498babcadSbeck if (greylist) { 32598babcadSbeck /* send this info to the greylister */ 32698babcadSbeck fprintf(grey, 32798babcadSbeck "SYNC\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n", 32898babcadSbeck helo, inet_ntoa(ip), from, to); 32998babcadSbeck fflush(grey); 33098babcadSbeck } 33198babcadSbeck break; 33298babcadSbeck case SPAM_SYNC_WHITE: 33398babcadSbeck sd = (struct spam_synctlv_addr *)tlv; 33498babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length)) 33598babcadSbeck goto trunc; 33698babcadSbeck 33798babcadSbeck ip.s_addr = (u_int32_t)ntohl(sd->sd_ip); 33898babcadSbeck expire = ntohl(sd->sd_expire); 33998babcadSbeck if (debug) { 34098babcadSbeck fprintf(stderr, "%s(sync): " 34198babcadSbeck "received white entry ", 34298babcadSbeck inet_ntoa(addr.sin_addr)); 34398babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip)); 34498babcadSbeck } 34598babcadSbeck if (greylist) { 34698babcadSbeck /* send this info to the greylister */ 34798babcadSbeck fprintf(grey, "WHITE:%s:", inet_ntoa(ip)); 34898babcadSbeck fprintf(grey, "%s:%u\n", 34998babcadSbeck inet_ntoa(addr.sin_addr), expire); 35098babcadSbeck fflush(grey); 35198babcadSbeck } 35298babcadSbeck break; 35398babcadSbeck case SPAM_SYNC_TRAPPED: 35498babcadSbeck sd = (struct spam_synctlv_addr *)tlv; 35598babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length)) 35698babcadSbeck goto trunc; 35798babcadSbeck 35898babcadSbeck ip.s_addr = (u_int32_t)ntohl(sd->sd_ip); 35998babcadSbeck expire = ntohl(sd->sd_expire); 36098babcadSbeck if (debug) { 36198babcadSbeck fprintf(stderr, "%s(sync): " 36298babcadSbeck "received trapped entry ", 36398babcadSbeck inet_ntoa(addr.sin_addr)); 36498babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip)); 36598babcadSbeck } 36698babcadSbeck if (greylist) { 36798babcadSbeck /* send this info to the greylister */ 36898babcadSbeck fprintf(grey, "TRAP:%s:", inet_ntoa(ip)); 36998babcadSbeck fprintf(grey, "%s:%u\n", 37098babcadSbeck inet_ntoa(addr.sin_addr), expire); 37198babcadSbeck fflush(grey); 37298babcadSbeck } 37398babcadSbeck break; 37498babcadSbeck case SPAM_SYNC_END: 37598babcadSbeck goto done; 37698babcadSbeck default: 37798babcadSbeck printf("invalid type: %d\n", ntohs(tlv->st_type)); 37898babcadSbeck goto trunc; 37998babcadSbeck } 38098babcadSbeck len -= ntohs(tlv->st_length); 38198babcadSbeck p = ((u_int8_t *)tlv) + ntohs(tlv->st_length); 38298babcadSbeck } 38398babcadSbeck 38498babcadSbeck done: 38598babcadSbeck return; 38698babcadSbeck 38798babcadSbeck trunc: 38898babcadSbeck if (debug) 38998babcadSbeck fprintf(stderr, "%s(sync): truncated or invalid packet\n", 39098babcadSbeck inet_ntoa(addr.sin_addr)); 39198babcadSbeck } 39298babcadSbeck 39398babcadSbeck void 39498babcadSbeck sync_send(struct iovec *iov, int iovlen) 39598babcadSbeck { 39698babcadSbeck struct sync_host *shost; 39798babcadSbeck struct msghdr msg; 39898babcadSbeck 39998babcadSbeck /* setup buffer */ 40098babcadSbeck bzero(&msg, sizeof(msg)); 40198babcadSbeck msg.msg_iov = iov; 40298babcadSbeck msg.msg_iovlen = iovlen; 40398babcadSbeck 40498babcadSbeck if (sendmcast) { 40598babcadSbeck if (debug) 40698babcadSbeck fprintf(stderr, "sending multicast sync message\n"); 40798babcadSbeck msg.msg_name = &sync_out; 40898babcadSbeck msg.msg_namelen = sizeof(sync_out); 40998babcadSbeck sendmsg(syncfd, &msg, 0); 41098babcadSbeck } 41198babcadSbeck 41298babcadSbeck LIST_FOREACH(shost, &sync_hosts, h_entry) { 41398babcadSbeck if (debug) 41498babcadSbeck fprintf(stderr, "sending sync message to %s (%s)\n", 415*f6c3b21dSotto shost->h_name, inet_ntoa(shost->sh_addr.sin_addr)); 416*f6c3b21dSotto msg.msg_name = &shost->sh_addr; 417*f6c3b21dSotto msg.msg_namelen = sizeof(shost->sh_addr); 41898babcadSbeck sendmsg(syncfd, &msg, 0); 41998babcadSbeck } 42098babcadSbeck } 42198babcadSbeck 42298babcadSbeck void 42398babcadSbeck sync_update(time_t now, char *helo, char *ip, char *from, char *to) 42498babcadSbeck { 42598babcadSbeck struct iovec iov[6]; 42698babcadSbeck struct spam_synchdr hdr; 42798babcadSbeck struct spam_synctlv_grey sg; 42898babcadSbeck struct spam_synctlv_hdr end; 42998babcadSbeck u_int16_t fromlen, tolen, helolen; 43098babcadSbeck int i = 0; 43198babcadSbeck HMAC_CTX ctx; 43298babcadSbeck u_int hmac_len; 43398babcadSbeck 43498babcadSbeck if (debug) 43598babcadSbeck fprintf(stderr, 43698babcadSbeck "sync grey update helo %s ip %s from %s to %s\n", 43798babcadSbeck helo, ip, from, to); 43898babcadSbeck 43998babcadSbeck bzero(&hdr, sizeof(hdr)); 44098babcadSbeck bzero(&sg, sizeof(sg)); 44198babcadSbeck 44298babcadSbeck fromlen = strlen(from) + 1; 44398babcadSbeck tolen = strlen(to) + 1; 44498babcadSbeck helolen = strlen(helo) + 1; 44598babcadSbeck 44698babcadSbeck HMAC_CTX_init(&ctx); 44798babcadSbeck HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); 44898babcadSbeck 44998babcadSbeck /* Add SPAM sync packet header */ 45098babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION; 45198babcadSbeck hdr.sh_af = AF_INET; 45298babcadSbeck hdr.sh_counter = sync_counter++; 45398babcadSbeck hdr.sh_length = htons(sizeof(hdr) + 45498babcadSbeck sizeof(sg) + fromlen + tolen + helolen + sizeof(end)); 45598babcadSbeck iov[i].iov_base = &hdr; 45698babcadSbeck iov[i].iov_len = sizeof(hdr); 45798babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 45898babcadSbeck i++; 45998babcadSbeck 46098babcadSbeck /* Add single SPAM sync greylisting entry */ 46198babcadSbeck sg.sg_type = htons(SPAM_SYNC_GREY); 46298babcadSbeck sg.sg_length = htons(sizeof(sg) + fromlen + helolen + tolen); 46398babcadSbeck sg.sg_timestamp = htonl(now); 46498babcadSbeck sg.sg_ip = htonl((u_int32_t)inet_addr(ip)); 46598babcadSbeck sg.sg_from_length = htons(fromlen); 46698babcadSbeck sg.sg_to_length = htons(tolen); 46798babcadSbeck sg.sg_helo_length = htons(helolen); 46898babcadSbeck iov[i].iov_base = &sg; 46998babcadSbeck iov[i].iov_len = sizeof(sg); 47098babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 47198babcadSbeck i++; 47298babcadSbeck 47398babcadSbeck iov[i].iov_base = from; 47498babcadSbeck iov[i].iov_len = fromlen; 47598babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 47698babcadSbeck i++; 47798babcadSbeck 47898babcadSbeck iov[i].iov_base = to; 47998babcadSbeck iov[i].iov_len = tolen; 48098babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 48198babcadSbeck i++; 48298babcadSbeck 48398babcadSbeck iov[i].iov_base = helo; 48498babcadSbeck iov[i].iov_len = helolen; 48598babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 48698babcadSbeck i++; 48798babcadSbeck 48898babcadSbeck /* Add end marker */ 48998babcadSbeck end.st_type = htons(SPAM_SYNC_END); 49098babcadSbeck end.st_length = htons(sizeof(end)); 49198babcadSbeck iov[i].iov_base = &end; 49298babcadSbeck iov[i].iov_len = sizeof(end); 49398babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 49498babcadSbeck i++; 49598babcadSbeck 49698babcadSbeck HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); 49798babcadSbeck 49898babcadSbeck /* Send message to the target hosts */ 49998babcadSbeck sync_send(iov, i); 5001d936ddfSbeck HMAC_CTX_cleanup(&ctx); 50198babcadSbeck } 50298babcadSbeck 50398babcadSbeck void 50498babcadSbeck sync_addr(time_t now, time_t expire, char *ip, u_int16_t type) 50598babcadSbeck { 50698babcadSbeck struct iovec iov[3]; 50798babcadSbeck struct spam_synchdr hdr; 50898babcadSbeck struct spam_synctlv_addr sd; 50998babcadSbeck struct spam_synctlv_hdr end; 51098babcadSbeck int i = 0; 51198babcadSbeck HMAC_CTX ctx; 51298babcadSbeck u_int hmac_len; 51398babcadSbeck 51498babcadSbeck if (debug) 51598babcadSbeck fprintf(stderr, "sync trapped %s\n", ip); 51698babcadSbeck 51798babcadSbeck bzero(&hdr, sizeof(hdr)); 51898babcadSbeck bzero(&sd, sizeof(sd)); 51998babcadSbeck 52098babcadSbeck HMAC_CTX_init(&ctx); 52198babcadSbeck HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); 52298babcadSbeck 52398babcadSbeck /* Add SPAM sync packet header */ 52498babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION; 52598babcadSbeck hdr.sh_af = AF_INET; 52698babcadSbeck hdr.sh_counter = sync_counter++; 52798babcadSbeck hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end)); 52898babcadSbeck iov[i].iov_base = &hdr; 52998babcadSbeck iov[i].iov_len = sizeof(hdr); 53098babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 53198babcadSbeck i++; 53298babcadSbeck 53398babcadSbeck /* Add single SPAM sync address entry */ 53498babcadSbeck sd.sd_type = htons(type); 53598babcadSbeck sd.sd_length = htons(sizeof(sd)); 53698babcadSbeck sd.sd_timestamp = htonl(now); 53798babcadSbeck sd.sd_expire = htonl(expire); 53898babcadSbeck sd.sd_ip = htonl((u_int32_t)inet_addr(ip)); 53998babcadSbeck iov[i].iov_base = &sd; 54098babcadSbeck iov[i].iov_len = sizeof(sd); 54198babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 54298babcadSbeck i++; 54398babcadSbeck 54498babcadSbeck /* Add end marker */ 54598babcadSbeck end.st_type = htons(SPAM_SYNC_END); 54698babcadSbeck end.st_length = htons(sizeof(end)); 54798babcadSbeck iov[i].iov_base = &end; 54898babcadSbeck iov[i].iov_len = sizeof(end); 54998babcadSbeck HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); 55098babcadSbeck i++; 55198babcadSbeck 55298babcadSbeck HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); 55398babcadSbeck 55498babcadSbeck /* Send message to the target hosts */ 55598babcadSbeck sync_send(iov, i); 5561d936ddfSbeck HMAC_CTX_cleanup(&ctx); 55798babcadSbeck } 55898babcadSbeck 55998babcadSbeck void 56098babcadSbeck sync_white(time_t now, time_t expire, char *ip) 56198babcadSbeck { 56298babcadSbeck if (debug) 56398babcadSbeck fprintf(stderr, "sync white address %s\n", ip); 56498babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_WHITE); 56598babcadSbeck } 56698babcadSbeck 56798babcadSbeck void 56898babcadSbeck sync_trapped(time_t now, time_t expire, char *ip) 56998babcadSbeck { 57098babcadSbeck if (debug) 57198babcadSbeck fprintf(stderr, "sync trapped address %s\n", ip); 57298babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_TRAPPED); 57398babcadSbeck } 574