1*4888f4f4Stb /* $OpenBSD: sync.c,v 1.14 2021/12/15 17:06:01 tb 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/socket.h>
2098babcadSbeck #include <sys/uio.h>
2198babcadSbeck #include <sys/ioctl.h>
2298babcadSbeck #include <sys/queue.h>
2398babcadSbeck
2498babcadSbeck #include <net/if.h>
2598babcadSbeck #include <netinet/in.h>
2698babcadSbeck #include <arpa/inet.h>
2798babcadSbeck
2898babcadSbeck #include <errno.h>
2998babcadSbeck #include <stdio.h>
3098babcadSbeck #include <stdlib.h>
3198babcadSbeck #include <string.h>
3298babcadSbeck #include <unistd.h>
3398babcadSbeck #include <sha1.h>
3498babcadSbeck #include <syslog.h>
35b6722e3fSderaadt #include <stdint.h>
3698babcadSbeck
3798babcadSbeck #include <netdb.h>
3898babcadSbeck
3998babcadSbeck #include <openssl/hmac.h>
4098babcadSbeck
4198babcadSbeck #include "sdl.h"
4298babcadSbeck #include "grey.h"
4398babcadSbeck #include "sync.h"
4498babcadSbeck
4598babcadSbeck extern struct syslog_data sdata;
4698babcadSbeck extern int debug;
4798babcadSbeck extern FILE *grey;
4898babcadSbeck extern int greylist;
4998babcadSbeck
5098babcadSbeck u_int32_t sync_counter;
5198babcadSbeck int syncfd;
5298babcadSbeck int sendmcast;
5398babcadSbeck struct sockaddr_in sync_in;
5498babcadSbeck struct sockaddr_in sync_out;
5598babcadSbeck static char *sync_key;
5698babcadSbeck
5798babcadSbeck struct sync_host {
5898babcadSbeck LIST_ENTRY(sync_host) h_entry;
5998babcadSbeck
6098babcadSbeck char *h_name;
61f6c3b21dSotto struct sockaddr_in sh_addr;
6298babcadSbeck };
6398babcadSbeck LIST_HEAD(synchosts, sync_host) sync_hosts = LIST_HEAD_INITIALIZER(sync_hosts);
6498babcadSbeck
6598babcadSbeck void sync_send(struct iovec *, int);
6698babcadSbeck void sync_addr(time_t, time_t, char *, u_int16_t);
6798babcadSbeck
6898babcadSbeck int
sync_addhost(const char * name,u_short port)6998babcadSbeck sync_addhost(const char *name, u_short port)
7098babcadSbeck {
7198babcadSbeck struct addrinfo hints, *res, *res0;
7298babcadSbeck struct sync_host *shost;
7398babcadSbeck struct sockaddr_in *addr = NULL;
7498babcadSbeck
75003af73dSmestre memset(&hints, 0, sizeof(hints));
7698babcadSbeck hints.ai_family = PF_UNSPEC;
7798babcadSbeck hints.ai_socktype = SOCK_STREAM;
7898babcadSbeck if (getaddrinfo(name, NULL, &hints, &res0) != 0)
7998babcadSbeck return (EINVAL);
8098babcadSbeck for (res = res0; res != NULL; res = res->ai_next) {
8198babcadSbeck if (addr == NULL && res->ai_family == AF_INET) {
8298babcadSbeck addr = (struct sockaddr_in *)res->ai_addr;
8398babcadSbeck break;
8498babcadSbeck }
8598babcadSbeck }
8698babcadSbeck if (addr == NULL) {
8798babcadSbeck freeaddrinfo(res0);
8898babcadSbeck return (EINVAL);
8998babcadSbeck }
9098babcadSbeck if ((shost = (struct sync_host *)
9198babcadSbeck calloc(1, sizeof(struct sync_host))) == NULL) {
9298babcadSbeck freeaddrinfo(res0);
9398babcadSbeck return (ENOMEM);
9498babcadSbeck }
9598babcadSbeck if ((shost->h_name = strdup(name)) == NULL) {
9698babcadSbeck free(shost);
9798babcadSbeck freeaddrinfo(res0);
9898babcadSbeck return (ENOMEM);
9998babcadSbeck }
10098babcadSbeck
101f6c3b21dSotto shost->sh_addr.sin_family = AF_INET;
102f6c3b21dSotto shost->sh_addr.sin_port = htons(port);
103f6c3b21dSotto shost->sh_addr.sin_addr.s_addr = addr->sin_addr.s_addr;
10498babcadSbeck freeaddrinfo(res0);
10598babcadSbeck
10698babcadSbeck LIST_INSERT_HEAD(&sync_hosts, shost, h_entry);
10798babcadSbeck
10898babcadSbeck if (debug)
10998babcadSbeck fprintf(stderr, "added spam sync host %s "
11098babcadSbeck "(address %s, port %d)\n", shost->h_name,
111f6c3b21dSotto inet_ntoa(shost->sh_addr.sin_addr), port);
11298babcadSbeck
11398babcadSbeck return (0);
11498babcadSbeck }
11598babcadSbeck
11698babcadSbeck int
sync_init(const char * iface,const char * baddr,u_short port)11798babcadSbeck sync_init(const char *iface, const char *baddr, u_short port)
11898babcadSbeck {
11998babcadSbeck int one = 1;
12098babcadSbeck u_int8_t ttl;
12198babcadSbeck struct ifreq ifr;
12298babcadSbeck struct ip_mreq mreq;
12398babcadSbeck struct sockaddr_in *addr;
12498babcadSbeck char ifnam[IFNAMSIZ], *ttlstr;
12598babcadSbeck const char *errstr;
12698babcadSbeck struct in_addr ina;
12798babcadSbeck
12898babcadSbeck if (iface != NULL)
12998babcadSbeck sendmcast++;
13098babcadSbeck
131003af73dSmestre memset(&ina, 0, sizeof(ina));
13298babcadSbeck if (baddr != NULL) {
13398babcadSbeck if (inet_pton(AF_INET, baddr, &ina) != 1) {
13498babcadSbeck ina.s_addr = htonl(INADDR_ANY);
13598babcadSbeck if (iface == NULL)
13698babcadSbeck iface = baddr;
13798babcadSbeck else if (iface != NULL && strcmp(baddr, iface) != 0) {
13898babcadSbeck fprintf(stderr, "multicast interface does "
13998babcadSbeck "not match");
14098babcadSbeck return (-1);
14198babcadSbeck }
14298babcadSbeck }
14398babcadSbeck }
14498babcadSbeck
14598babcadSbeck sync_key = SHA1File(SPAM_SYNC_KEY, NULL);
14698babcadSbeck if (sync_key == NULL) {
14798babcadSbeck if (errno != ENOENT) {
14898babcadSbeck fprintf(stderr, "failed to open sync key: %s\n",
14998babcadSbeck strerror(errno));
15098babcadSbeck return (-1);
15198babcadSbeck }
15298babcadSbeck /* Use empty key by default */
15398babcadSbeck sync_key = "";
15498babcadSbeck }
15598babcadSbeck
15698babcadSbeck syncfd = socket(AF_INET, SOCK_DGRAM, 0);
15798babcadSbeck if (syncfd == -1)
15898babcadSbeck return (-1);
15998babcadSbeck
16098babcadSbeck if (setsockopt(syncfd, SOL_SOCKET, SO_REUSEADDR, &one,
16198babcadSbeck sizeof(one)) == -1)
16298babcadSbeck goto fail;
16398babcadSbeck
164003af73dSmestre memset(&sync_out, 0, sizeof(sync_out));
16598babcadSbeck sync_out.sin_family = AF_INET;
16698babcadSbeck sync_out.sin_len = sizeof(sync_out);
16798babcadSbeck sync_out.sin_addr.s_addr = ina.s_addr;
16898babcadSbeck if (baddr == NULL && iface == NULL)
16998babcadSbeck sync_out.sin_port = 0;
17098babcadSbeck else
17198babcadSbeck sync_out.sin_port = htons(port);
17298babcadSbeck
17398babcadSbeck if (bind(syncfd, (struct sockaddr *)&sync_out, sizeof(sync_out)) == -1)
17498babcadSbeck goto fail;
17598babcadSbeck
17698babcadSbeck /* Don't use multicast messages */
17798babcadSbeck if (iface == NULL)
17898babcadSbeck return (syncfd);
17998babcadSbeck
18098babcadSbeck strlcpy(ifnam, iface, sizeof(ifnam));
18198babcadSbeck ttl = SPAM_SYNC_MCASTTTL;
18298babcadSbeck if ((ttlstr = strchr(ifnam, ':')) != NULL) {
18398babcadSbeck *ttlstr++ = '\0';
18498babcadSbeck ttl = (u_int8_t)strtonum(ttlstr, 1, UINT8_MAX, &errstr);
18598babcadSbeck if (errstr) {
18698babcadSbeck fprintf(stderr, "invalid multicast ttl %s: %s",
18798babcadSbeck ttlstr, errstr);
18898babcadSbeck goto fail;
18998babcadSbeck }
19098babcadSbeck }
19198babcadSbeck
192003af73dSmestre memset(&ifr, 0, sizeof(ifr));
19398babcadSbeck strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name));
19498babcadSbeck if (ioctl(syncfd, SIOCGIFADDR, &ifr) == -1)
19598babcadSbeck goto fail;
19698babcadSbeck
197003af73dSmestre memset(&sync_in, 0, sizeof(sync_in));
19898babcadSbeck addr = (struct sockaddr_in *)&ifr.ifr_addr;
19998babcadSbeck sync_in.sin_family = AF_INET;
20098babcadSbeck sync_in.sin_len = sizeof(sync_in);
20198babcadSbeck sync_in.sin_addr.s_addr = addr->sin_addr.s_addr;
20298babcadSbeck sync_in.sin_port = htons(port);
20398babcadSbeck
204003af73dSmestre memset(&mreq, 0, sizeof(mreq));
20598babcadSbeck sync_out.sin_addr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR);
20698babcadSbeck mreq.imr_multiaddr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR);
20798babcadSbeck mreq.imr_interface.s_addr = sync_in.sin_addr.s_addr;
20898babcadSbeck
20998babcadSbeck if (setsockopt(syncfd, IPPROTO_IP,
21098babcadSbeck IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
21198babcadSbeck fprintf(stderr, "failed to add multicast membership to %s: %s",
21298babcadSbeck SPAM_SYNC_MCASTADDR, strerror(errno));
21398babcadSbeck goto fail;
21498babcadSbeck }
21598babcadSbeck if (setsockopt(syncfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
216df69c215Sderaadt sizeof(ttl)) == -1) {
21798babcadSbeck fprintf(stderr, "failed to set multicast ttl to "
21898babcadSbeck "%u: %s\n", ttl, strerror(errno));
21998babcadSbeck setsockopt(syncfd, IPPROTO_IP,
22098babcadSbeck IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
22198babcadSbeck goto fail;
22298babcadSbeck }
22398babcadSbeck
22498babcadSbeck if (debug)
22598babcadSbeck printf("using multicast spam sync %smode "
22698babcadSbeck "(ttl %u, group %s, port %d)\n",
22798babcadSbeck sendmcast ? "" : "receive ",
22898babcadSbeck ttl, inet_ntoa(sync_out.sin_addr), port);
22998babcadSbeck
23098babcadSbeck return (syncfd);
23198babcadSbeck
23298babcadSbeck fail:
23398babcadSbeck close(syncfd);
23498babcadSbeck return (-1);
23598babcadSbeck }
23698babcadSbeck
23798babcadSbeck void
sync_recv(void)23898babcadSbeck sync_recv(void)
23998babcadSbeck {
24098babcadSbeck struct spam_synchdr *hdr;
24198babcadSbeck struct sockaddr_in addr;
24298babcadSbeck struct spam_synctlv_hdr *tlv;
24398babcadSbeck struct spam_synctlv_grey *sg;
24498babcadSbeck struct spam_synctlv_addr *sd;
24598babcadSbeck u_int8_t buf[SPAM_SYNC_MAXSIZE];
24698babcadSbeck u_int8_t hmac[2][SPAM_SYNC_HMAC_LEN];
24798babcadSbeck struct in_addr ip;
24898babcadSbeck char *from, *to, *helo;
24998babcadSbeck u_int8_t *p;
25098babcadSbeck socklen_t addr_len;
25198babcadSbeck ssize_t len;
25298babcadSbeck u_int hmac_len;
253d614df11Sderaadt u_int32_t expire;
25498babcadSbeck
255003af73dSmestre memset(&addr, 0, sizeof(addr));
256003af73dSmestre memset(buf, 0, sizeof(buf));
25798babcadSbeck
25898babcadSbeck addr_len = sizeof(addr);
25998babcadSbeck if ((len = recvfrom(syncfd, buf, sizeof(buf), 0,
26098babcadSbeck (struct sockaddr *)&addr, &addr_len)) < 1)
26198babcadSbeck return;
26298babcadSbeck if (addr.sin_addr.s_addr != htonl(INADDR_ANY) &&
26398babcadSbeck bcmp(&sync_in.sin_addr, &addr.sin_addr,
26498babcadSbeck sizeof(addr.sin_addr)) == 0)
26598babcadSbeck return;
26698babcadSbeck
26798babcadSbeck /* Ignore invalid or truncated packets */
26898babcadSbeck hdr = (struct spam_synchdr *)buf;
269544df9d5Sreyk if (len < sizeof(struct spam_synchdr) ||
270544df9d5Sreyk hdr->sh_version != SPAM_SYNC_VERSION ||
27198babcadSbeck hdr->sh_af != AF_INET ||
27298babcadSbeck len < ntohs(hdr->sh_length))
27398babcadSbeck goto trunc;
27498babcadSbeck len = ntohs(hdr->sh_length);
27598babcadSbeck
27698babcadSbeck /* Compute and validate HMAC */
277003af73dSmestre memcpy(hmac[0], hdr->sh_hmac, SPAM_SYNC_HMAC_LEN);
278003af73dSmestre explicit_bzero(hdr->sh_hmac, SPAM_SYNC_HMAC_LEN);
27998babcadSbeck HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len,
28098babcadSbeck hmac[1], &hmac_len);
28198babcadSbeck if (bcmp(hmac[0], hmac[1], SPAM_SYNC_HMAC_LEN) != 0)
28298babcadSbeck goto trunc;
28398babcadSbeck
28498babcadSbeck if (debug)
28598babcadSbeck fprintf(stderr,
28698babcadSbeck "%s(sync): received packet of %d bytes\n",
28798babcadSbeck inet_ntoa(addr.sin_addr), (int)len);
28898babcadSbeck
28998babcadSbeck p = (u_int8_t *)(hdr + 1);
29098babcadSbeck while (len) {
29198babcadSbeck tlv = (struct spam_synctlv_hdr *)p;
29298babcadSbeck
293fcca1eedSreyk if (len < sizeof(struct spam_synctlv_hdr) ||
294fcca1eedSreyk len < ntohs(tlv->st_length))
29598babcadSbeck goto trunc;
29698babcadSbeck
29798babcadSbeck switch (ntohs(tlv->st_type)) {
29898babcadSbeck case SPAM_SYNC_GREY:
29998babcadSbeck sg = (struct spam_synctlv_grey *)tlv;
30098babcadSbeck if ((sizeof(*sg) +
30198babcadSbeck ntohs(sg->sg_from_length) +
30298babcadSbeck ntohs(sg->sg_to_length) +
30398babcadSbeck ntohs(sg->sg_helo_length)) >
30498babcadSbeck ntohs(tlv->st_length))
30598babcadSbeck goto trunc;
30698babcadSbeck
307d72b910dSderaadt ip.s_addr = sg->sg_ip;
30898babcadSbeck from = (char *)(sg + 1);
30998babcadSbeck to = from + ntohs(sg->sg_from_length);
31098babcadSbeck helo = to + ntohs(sg->sg_to_length);
31198babcadSbeck if (debug) {
31298babcadSbeck fprintf(stderr, "%s(sync): "
31398babcadSbeck "received grey entry ",
31498babcadSbeck inet_ntoa(addr.sin_addr));
31598babcadSbeck fprintf(stderr, "helo %s ip %s "
31698babcadSbeck "from %s to %s\n",
31798babcadSbeck helo, inet_ntoa(ip), from, to);
31898babcadSbeck }
31998babcadSbeck if (greylist) {
32098babcadSbeck /* send this info to the greylister */
32198babcadSbeck fprintf(grey,
32298babcadSbeck "SYNC\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n",
32398babcadSbeck helo, inet_ntoa(ip), from, to);
32498babcadSbeck fflush(grey);
32598babcadSbeck }
32698babcadSbeck break;
32798babcadSbeck case SPAM_SYNC_WHITE:
32898babcadSbeck sd = (struct spam_synctlv_addr *)tlv;
32998babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length))
33098babcadSbeck goto trunc;
33198babcadSbeck
332d72b910dSderaadt ip.s_addr = sd->sd_ip;
33398babcadSbeck expire = ntohl(sd->sd_expire);
33498babcadSbeck if (debug) {
33598babcadSbeck fprintf(stderr, "%s(sync): "
33698babcadSbeck "received white entry ",
33798babcadSbeck inet_ntoa(addr.sin_addr));
33898babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip));
33998babcadSbeck }
34098babcadSbeck if (greylist) {
34198babcadSbeck /* send this info to the greylister */
34298babcadSbeck fprintf(grey, "WHITE:%s:", inet_ntoa(ip));
34398babcadSbeck fprintf(grey, "%s:%u\n",
34498babcadSbeck inet_ntoa(addr.sin_addr), expire);
34598babcadSbeck fflush(grey);
34698babcadSbeck }
34798babcadSbeck break;
34898babcadSbeck case SPAM_SYNC_TRAPPED:
34998babcadSbeck sd = (struct spam_synctlv_addr *)tlv;
35098babcadSbeck if (sizeof(*sd) != ntohs(tlv->st_length))
35198babcadSbeck goto trunc;
35298babcadSbeck
353d72b910dSderaadt ip.s_addr = sd->sd_ip;
35498babcadSbeck expire = ntohl(sd->sd_expire);
35598babcadSbeck if (debug) {
35698babcadSbeck fprintf(stderr, "%s(sync): "
35798babcadSbeck "received trapped entry ",
35898babcadSbeck inet_ntoa(addr.sin_addr));
35998babcadSbeck fprintf(stderr, "ip %s ", inet_ntoa(ip));
36098babcadSbeck }
36198babcadSbeck if (greylist) {
36298babcadSbeck /* send this info to the greylister */
36398babcadSbeck fprintf(grey, "TRAP:%s:", inet_ntoa(ip));
36498babcadSbeck fprintf(grey, "%s:%u\n",
36598babcadSbeck inet_ntoa(addr.sin_addr), expire);
36698babcadSbeck fflush(grey);
36798babcadSbeck }
36898babcadSbeck break;
36998babcadSbeck case SPAM_SYNC_END:
37098babcadSbeck goto done;
37198babcadSbeck default:
37298babcadSbeck printf("invalid type: %d\n", ntohs(tlv->st_type));
37398babcadSbeck goto trunc;
37498babcadSbeck }
37598babcadSbeck len -= ntohs(tlv->st_length);
37698babcadSbeck p = ((u_int8_t *)tlv) + ntohs(tlv->st_length);
37798babcadSbeck }
37898babcadSbeck
37998babcadSbeck done:
38098babcadSbeck return;
38198babcadSbeck
38298babcadSbeck trunc:
38398babcadSbeck if (debug)
38498babcadSbeck fprintf(stderr, "%s(sync): truncated or invalid packet\n",
38598babcadSbeck inet_ntoa(addr.sin_addr));
38698babcadSbeck }
38798babcadSbeck
38898babcadSbeck void
sync_send(struct iovec * iov,int iovlen)38998babcadSbeck sync_send(struct iovec *iov, int iovlen)
39098babcadSbeck {
39198babcadSbeck struct sync_host *shost;
39298babcadSbeck struct msghdr msg;
39398babcadSbeck
39498babcadSbeck /* setup buffer */
395003af73dSmestre memset(&msg, 0, sizeof(msg));
39698babcadSbeck msg.msg_iov = iov;
39798babcadSbeck msg.msg_iovlen = iovlen;
39898babcadSbeck
39998babcadSbeck if (sendmcast) {
40098babcadSbeck if (debug)
40198babcadSbeck fprintf(stderr, "sending multicast sync message\n");
40298babcadSbeck msg.msg_name = &sync_out;
40398babcadSbeck msg.msg_namelen = sizeof(sync_out);
40498babcadSbeck sendmsg(syncfd, &msg, 0);
40598babcadSbeck }
40698babcadSbeck
40798babcadSbeck LIST_FOREACH(shost, &sync_hosts, h_entry) {
40898babcadSbeck if (debug)
40998babcadSbeck fprintf(stderr, "sending sync message to %s (%s)\n",
410f6c3b21dSotto shost->h_name, inet_ntoa(shost->sh_addr.sin_addr));
411f6c3b21dSotto msg.msg_name = &shost->sh_addr;
412f6c3b21dSotto msg.msg_namelen = sizeof(shost->sh_addr);
41398babcadSbeck sendmsg(syncfd, &msg, 0);
41498babcadSbeck }
41598babcadSbeck }
41698babcadSbeck
41798babcadSbeck void
sync_update(time_t now,char * helo,char * ip,char * from,char * to)41898babcadSbeck sync_update(time_t now, char *helo, char *ip, char *from, char *to)
41998babcadSbeck {
4204aba4ff9Sderaadt struct iovec iov[7];
42198babcadSbeck struct spam_synchdr hdr;
42298babcadSbeck struct spam_synctlv_grey sg;
42398babcadSbeck struct spam_synctlv_hdr end;
4244aba4ff9Sderaadt u_int16_t sglen, fromlen, tolen, helolen, padlen;
4254aba4ff9Sderaadt char pad[SPAM_ALIGNBYTES];
42698babcadSbeck int i = 0;
427*4888f4f4Stb HMAC_CTX *ctx;
42898babcadSbeck u_int hmac_len;
42998babcadSbeck
43098babcadSbeck if (debug)
43198babcadSbeck fprintf(stderr,
43298babcadSbeck "sync grey update helo %s ip %s from %s to %s\n",
43398babcadSbeck helo, ip, from, to);
43498babcadSbeck
435003af73dSmestre memset(&hdr, 0, sizeof(hdr));
436003af73dSmestre memset(&sg, 0, sizeof(sg));
437003af73dSmestre memset(&pad, 0, sizeof(pad));
43898babcadSbeck
43998babcadSbeck fromlen = strlen(from) + 1;
44098babcadSbeck tolen = strlen(to) + 1;
44198babcadSbeck helolen = strlen(helo) + 1;
44298babcadSbeck
443*4888f4f4Stb if ((ctx = HMAC_CTX_new()) == NULL)
444*4888f4f4Stb goto bad;
445*4888f4f4Stb if (!HMAC_Init_ex(ctx, sync_key, strlen(sync_key), EVP_sha1(), NULL))
446*4888f4f4Stb goto bad;
44798babcadSbeck
4484aba4ff9Sderaadt sglen = sizeof(sg) + fromlen + tolen + helolen;
4494aba4ff9Sderaadt padlen = SPAM_ALIGN(sglen) - sglen;
4504aba4ff9Sderaadt
45198babcadSbeck /* Add SPAM sync packet header */
45298babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION;
45398babcadSbeck hdr.sh_af = AF_INET;
454d72b910dSderaadt hdr.sh_counter = htonl(sync_counter++);
4554aba4ff9Sderaadt hdr.sh_length = htons(sizeof(hdr) + sglen + padlen + sizeof(end));
45698babcadSbeck iov[i].iov_base = &hdr;
45798babcadSbeck iov[i].iov_len = sizeof(hdr);
458*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
459*4888f4f4Stb goto bad;
46098babcadSbeck i++;
46198babcadSbeck
46298babcadSbeck /* Add single SPAM sync greylisting entry */
46398babcadSbeck sg.sg_type = htons(SPAM_SYNC_GREY);
4644aba4ff9Sderaadt sg.sg_length = htons(sglen + padlen);
46598babcadSbeck sg.sg_timestamp = htonl(now);
466d72b910dSderaadt sg.sg_ip = inet_addr(ip);
46798babcadSbeck sg.sg_from_length = htons(fromlen);
46898babcadSbeck sg.sg_to_length = htons(tolen);
46998babcadSbeck sg.sg_helo_length = htons(helolen);
47098babcadSbeck iov[i].iov_base = &sg;
47198babcadSbeck iov[i].iov_len = sizeof(sg);
472*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
473*4888f4f4Stb goto bad;
47498babcadSbeck i++;
47598babcadSbeck
47698babcadSbeck iov[i].iov_base = from;
47798babcadSbeck iov[i].iov_len = fromlen;
478*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
479*4888f4f4Stb goto bad;
48098babcadSbeck i++;
48198babcadSbeck
48298babcadSbeck iov[i].iov_base = to;
48398babcadSbeck iov[i].iov_len = tolen;
484*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
485*4888f4f4Stb goto bad;
48698babcadSbeck i++;
48798babcadSbeck
48898babcadSbeck iov[i].iov_base = helo;
48998babcadSbeck iov[i].iov_len = helolen;
490*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
491*4888f4f4Stb goto bad;
49298babcadSbeck i++;
49398babcadSbeck
4944aba4ff9Sderaadt iov[i].iov_base = pad;
4954aba4ff9Sderaadt iov[i].iov_len = padlen;
496*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
497*4888f4f4Stb goto bad;
4984aba4ff9Sderaadt i++;
4994aba4ff9Sderaadt
50098babcadSbeck /* Add end marker */
50198babcadSbeck end.st_type = htons(SPAM_SYNC_END);
50298babcadSbeck end.st_length = htons(sizeof(end));
50398babcadSbeck iov[i].iov_base = &end;
50498babcadSbeck iov[i].iov_len = sizeof(end);
505*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
506*4888f4f4Stb goto bad;
50798babcadSbeck i++;
50898babcadSbeck
509*4888f4f4Stb if (!HMAC_Final(ctx, hdr.sh_hmac, &hmac_len))
510*4888f4f4Stb goto bad;
51198babcadSbeck
51298babcadSbeck /* Send message to the target hosts */
51398babcadSbeck sync_send(iov, i);
514*4888f4f4Stb
515*4888f4f4Stb bad:
516*4888f4f4Stb HMAC_CTX_free(ctx);
51798babcadSbeck }
51898babcadSbeck
51998babcadSbeck void
sync_addr(time_t now,time_t expire,char * ip,u_int16_t type)52098babcadSbeck sync_addr(time_t now, time_t expire, char *ip, u_int16_t type)
52198babcadSbeck {
52298babcadSbeck struct iovec iov[3];
52398babcadSbeck struct spam_synchdr hdr;
52498babcadSbeck struct spam_synctlv_addr sd;
52598babcadSbeck struct spam_synctlv_hdr end;
52698babcadSbeck int i = 0;
527*4888f4f4Stb HMAC_CTX *ctx;
52898babcadSbeck u_int hmac_len;
52998babcadSbeck
53098babcadSbeck if (debug)
53100ddf0caSbeck fprintf(stderr, "sync %s %s\n",
53200ddf0caSbeck type == SPAM_SYNC_WHITE ? "white" : "trapped", ip);
53398babcadSbeck
534003af73dSmestre memset(&hdr, 0, sizeof(hdr));
535003af73dSmestre memset(&sd, 0, sizeof(sd));
53698babcadSbeck
537*4888f4f4Stb if ((ctx = HMAC_CTX_new()) == NULL)
538*4888f4f4Stb goto bad;
539*4888f4f4Stb if (!HMAC_Init_ex(ctx, sync_key, strlen(sync_key), EVP_sha1(), NULL))
540*4888f4f4Stb goto bad;
54198babcadSbeck
54298babcadSbeck /* Add SPAM sync packet header */
54398babcadSbeck hdr.sh_version = SPAM_SYNC_VERSION;
54498babcadSbeck hdr.sh_af = AF_INET;
545d72b910dSderaadt hdr.sh_counter = htonl(sync_counter++);
54698babcadSbeck hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end));
54798babcadSbeck iov[i].iov_base = &hdr;
54898babcadSbeck iov[i].iov_len = sizeof(hdr);
549*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
550*4888f4f4Stb goto bad;
55198babcadSbeck i++;
55298babcadSbeck
55398babcadSbeck /* Add single SPAM sync address entry */
55498babcadSbeck sd.sd_type = htons(type);
55598babcadSbeck sd.sd_length = htons(sizeof(sd));
55698babcadSbeck sd.sd_timestamp = htonl(now);
55798babcadSbeck sd.sd_expire = htonl(expire);
558d72b910dSderaadt sd.sd_ip = inet_addr(ip);
55998babcadSbeck iov[i].iov_base = &sd;
56098babcadSbeck iov[i].iov_len = sizeof(sd);
561*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
562*4888f4f4Stb goto bad;
56398babcadSbeck i++;
56498babcadSbeck
56598babcadSbeck /* Add end marker */
56698babcadSbeck end.st_type = htons(SPAM_SYNC_END);
56798babcadSbeck end.st_length = htons(sizeof(end));
56898babcadSbeck iov[i].iov_base = &end;
56998babcadSbeck iov[i].iov_len = sizeof(end);
570*4888f4f4Stb if (!HMAC_Update(ctx, iov[i].iov_base, iov[i].iov_len))
571*4888f4f4Stb goto bad;
57298babcadSbeck i++;
57398babcadSbeck
574*4888f4f4Stb if (!HMAC_Final(ctx, hdr.sh_hmac, &hmac_len))
575*4888f4f4Stb goto bad;
57698babcadSbeck
57798babcadSbeck /* Send message to the target hosts */
57898babcadSbeck sync_send(iov, i);
579*4888f4f4Stb
580*4888f4f4Stb bad:
581*4888f4f4Stb HMAC_CTX_free(ctx);
58298babcadSbeck }
58398babcadSbeck
58498babcadSbeck void
sync_white(time_t now,time_t expire,char * ip)58598babcadSbeck sync_white(time_t now, time_t expire, char *ip)
58698babcadSbeck {
58798babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_WHITE);
58898babcadSbeck }
58998babcadSbeck
59098babcadSbeck void
sync_trapped(time_t now,time_t expire,char * ip)59198babcadSbeck sync_trapped(time_t now, time_t expire, char *ip)
59298babcadSbeck {
59398babcadSbeck sync_addr(now, expire, ip, SPAM_SYNC_TRAPPED);
59498babcadSbeck }
595