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