xref: /openbsd/libexec/spamd/sync.c (revision 4888f4f4)
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