1 |
|
|
/* $OpenBSD: sync.c,v 1.12 2016/10/20 21:09:46 mestre Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/socket.h> |
20 |
|
|
#include <sys/uio.h> |
21 |
|
|
#include <sys/ioctl.h> |
22 |
|
|
#include <sys/queue.h> |
23 |
|
|
|
24 |
|
|
#include <net/if.h> |
25 |
|
|
#include <netinet/in.h> |
26 |
|
|
#include <arpa/inet.h> |
27 |
|
|
|
28 |
|
|
#include <errno.h> |
29 |
|
|
#include <stdio.h> |
30 |
|
|
#include <stdlib.h> |
31 |
|
|
#include <string.h> |
32 |
|
|
#include <unistd.h> |
33 |
|
|
#include <sha1.h> |
34 |
|
|
#include <syslog.h> |
35 |
|
|
#include <stdint.h> |
36 |
|
|
|
37 |
|
|
#include <netdb.h> |
38 |
|
|
|
39 |
|
|
#include <openssl/hmac.h> |
40 |
|
|
|
41 |
|
|
#include "sdl.h" |
42 |
|
|
#include "grey.h" |
43 |
|
|
#include "sync.h" |
44 |
|
|
|
45 |
|
|
extern struct syslog_data sdata; |
46 |
|
|
extern int debug; |
47 |
|
|
extern FILE *grey; |
48 |
|
|
extern int greylist; |
49 |
|
|
|
50 |
|
|
u_int32_t sync_counter; |
51 |
|
|
int syncfd; |
52 |
|
|
int sendmcast; |
53 |
|
|
struct sockaddr_in sync_in; |
54 |
|
|
struct sockaddr_in sync_out; |
55 |
|
|
static char *sync_key; |
56 |
|
|
|
57 |
|
|
struct sync_host { |
58 |
|
|
LIST_ENTRY(sync_host) h_entry; |
59 |
|
|
|
60 |
|
|
char *h_name; |
61 |
|
|
struct sockaddr_in sh_addr; |
62 |
|
|
}; |
63 |
|
|
LIST_HEAD(synchosts, sync_host) sync_hosts = LIST_HEAD_INITIALIZER(sync_hosts); |
64 |
|
|
|
65 |
|
|
void sync_send(struct iovec *, int); |
66 |
|
|
void sync_addr(time_t, time_t, char *, u_int16_t); |
67 |
|
|
|
68 |
|
|
int |
69 |
|
|
sync_addhost(const char *name, u_short port) |
70 |
|
|
{ |
71 |
|
|
struct addrinfo hints, *res, *res0; |
72 |
|
|
struct sync_host *shost; |
73 |
|
|
struct sockaddr_in *addr = NULL; |
74 |
|
|
|
75 |
|
|
memset(&hints, 0, sizeof(hints)); |
76 |
|
|
hints.ai_family = PF_UNSPEC; |
77 |
|
|
hints.ai_socktype = SOCK_STREAM; |
78 |
|
|
if (getaddrinfo(name, NULL, &hints, &res0) != 0) |
79 |
|
|
return (EINVAL); |
80 |
|
|
for (res = res0; res != NULL; res = res->ai_next) { |
81 |
|
|
if (addr == NULL && res->ai_family == AF_INET) { |
82 |
|
|
addr = (struct sockaddr_in *)res->ai_addr; |
83 |
|
|
break; |
84 |
|
|
} |
85 |
|
|
} |
86 |
|
|
if (addr == NULL) { |
87 |
|
|
freeaddrinfo(res0); |
88 |
|
|
return (EINVAL); |
89 |
|
|
} |
90 |
|
|
if ((shost = (struct sync_host *) |
91 |
|
|
calloc(1, sizeof(struct sync_host))) == NULL) { |
92 |
|
|
freeaddrinfo(res0); |
93 |
|
|
return (ENOMEM); |
94 |
|
|
} |
95 |
|
|
if ((shost->h_name = strdup(name)) == NULL) { |
96 |
|
|
free(shost); |
97 |
|
|
freeaddrinfo(res0); |
98 |
|
|
return (ENOMEM); |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
shost->sh_addr.sin_family = AF_INET; |
102 |
|
|
shost->sh_addr.sin_port = htons(port); |
103 |
|
|
shost->sh_addr.sin_addr.s_addr = addr->sin_addr.s_addr; |
104 |
|
|
freeaddrinfo(res0); |
105 |
|
|
|
106 |
|
|
LIST_INSERT_HEAD(&sync_hosts, shost, h_entry); |
107 |
|
|
|
108 |
|
|
if (debug) |
109 |
|
|
fprintf(stderr, "added spam sync host %s " |
110 |
|
|
"(address %s, port %d)\n", shost->h_name, |
111 |
|
|
inet_ntoa(shost->sh_addr.sin_addr), port); |
112 |
|
|
|
113 |
|
|
return (0); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
int |
117 |
|
|
sync_init(const char *iface, const char *baddr, u_short port) |
118 |
|
|
{ |
119 |
|
|
int one = 1; |
120 |
|
|
u_int8_t ttl; |
121 |
|
|
struct ifreq ifr; |
122 |
|
|
struct ip_mreq mreq; |
123 |
|
|
struct sockaddr_in *addr; |
124 |
|
|
char ifnam[IFNAMSIZ], *ttlstr; |
125 |
|
|
const char *errstr; |
126 |
|
|
struct in_addr ina; |
127 |
|
|
|
128 |
|
|
if (iface != NULL) |
129 |
|
|
sendmcast++; |
130 |
|
|
|
131 |
|
|
memset(&ina, 0, sizeof(ina)); |
132 |
|
|
if (baddr != NULL) { |
133 |
|
|
if (inet_pton(AF_INET, baddr, &ina) != 1) { |
134 |
|
|
ina.s_addr = htonl(INADDR_ANY); |
135 |
|
|
if (iface == NULL) |
136 |
|
|
iface = baddr; |
137 |
|
|
else if (iface != NULL && strcmp(baddr, iface) != 0) { |
138 |
|
|
fprintf(stderr, "multicast interface does " |
139 |
|
|
"not match"); |
140 |
|
|
return (-1); |
141 |
|
|
} |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
sync_key = SHA1File(SPAM_SYNC_KEY, NULL); |
146 |
|
|
if (sync_key == NULL) { |
147 |
|
|
if (errno != ENOENT) { |
148 |
|
|
fprintf(stderr, "failed to open sync key: %s\n", |
149 |
|
|
strerror(errno)); |
150 |
|
|
return (-1); |
151 |
|
|
} |
152 |
|
|
/* Use empty key by default */ |
153 |
|
|
sync_key = ""; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
syncfd = socket(AF_INET, SOCK_DGRAM, 0); |
157 |
|
|
if (syncfd == -1) |
158 |
|
|
return (-1); |
159 |
|
|
|
160 |
|
|
if (setsockopt(syncfd, SOL_SOCKET, SO_REUSEADDR, &one, |
161 |
|
|
sizeof(one)) == -1) |
162 |
|
|
goto fail; |
163 |
|
|
|
164 |
|
|
memset(&sync_out, 0, sizeof(sync_out)); |
165 |
|
|
sync_out.sin_family = AF_INET; |
166 |
|
|
sync_out.sin_len = sizeof(sync_out); |
167 |
|
|
sync_out.sin_addr.s_addr = ina.s_addr; |
168 |
|
|
if (baddr == NULL && iface == NULL) |
169 |
|
|
sync_out.sin_port = 0; |
170 |
|
|
else |
171 |
|
|
sync_out.sin_port = htons(port); |
172 |
|
|
|
173 |
|
|
if (bind(syncfd, (struct sockaddr *)&sync_out, sizeof(sync_out)) == -1) |
174 |
|
|
goto fail; |
175 |
|
|
|
176 |
|
|
/* Don't use multicast messages */ |
177 |
|
|
if (iface == NULL) |
178 |
|
|
return (syncfd); |
179 |
|
|
|
180 |
|
|
strlcpy(ifnam, iface, sizeof(ifnam)); |
181 |
|
|
ttl = SPAM_SYNC_MCASTTTL; |
182 |
|
|
if ((ttlstr = strchr(ifnam, ':')) != NULL) { |
183 |
|
|
*ttlstr++ = '\0'; |
184 |
|
|
ttl = (u_int8_t)strtonum(ttlstr, 1, UINT8_MAX, &errstr); |
185 |
|
|
if (errstr) { |
186 |
|
|
fprintf(stderr, "invalid multicast ttl %s: %s", |
187 |
|
|
ttlstr, errstr); |
188 |
|
|
goto fail; |
189 |
|
|
} |
190 |
|
|
} |
191 |
|
|
|
192 |
|
|
memset(&ifr, 0, sizeof(ifr)); |
193 |
|
|
strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); |
194 |
|
|
if (ioctl(syncfd, SIOCGIFADDR, &ifr) == -1) |
195 |
|
|
goto fail; |
196 |
|
|
|
197 |
|
|
memset(&sync_in, 0, sizeof(sync_in)); |
198 |
|
|
addr = (struct sockaddr_in *)&ifr.ifr_addr; |
199 |
|
|
sync_in.sin_family = AF_INET; |
200 |
|
|
sync_in.sin_len = sizeof(sync_in); |
201 |
|
|
sync_in.sin_addr.s_addr = addr->sin_addr.s_addr; |
202 |
|
|
sync_in.sin_port = htons(port); |
203 |
|
|
|
204 |
|
|
memset(&mreq, 0, sizeof(mreq)); |
205 |
|
|
sync_out.sin_addr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR); |
206 |
|
|
mreq.imr_multiaddr.s_addr = inet_addr(SPAM_SYNC_MCASTADDR); |
207 |
|
|
mreq.imr_interface.s_addr = sync_in.sin_addr.s_addr; |
208 |
|
|
|
209 |
|
|
if (setsockopt(syncfd, IPPROTO_IP, |
210 |
|
|
IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { |
211 |
|
|
fprintf(stderr, "failed to add multicast membership to %s: %s", |
212 |
|
|
SPAM_SYNC_MCASTADDR, strerror(errno)); |
213 |
|
|
goto fail; |
214 |
|
|
} |
215 |
|
|
if (setsockopt(syncfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, |
216 |
|
|
sizeof(ttl)) < 0) { |
217 |
|
|
fprintf(stderr, "failed to set multicast ttl to " |
218 |
|
|
"%u: %s\n", ttl, strerror(errno)); |
219 |
|
|
setsockopt(syncfd, IPPROTO_IP, |
220 |
|
|
IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); |
221 |
|
|
goto fail; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
if (debug) |
225 |
|
|
printf("using multicast spam sync %smode " |
226 |
|
|
"(ttl %u, group %s, port %d)\n", |
227 |
|
|
sendmcast ? "" : "receive ", |
228 |
|
|
ttl, inet_ntoa(sync_out.sin_addr), port); |
229 |
|
|
|
230 |
|
|
return (syncfd); |
231 |
|
|
|
232 |
|
|
fail: |
233 |
|
|
close(syncfd); |
234 |
|
|
return (-1); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
void |
238 |
|
|
sync_recv(void) |
239 |
|
|
{ |
240 |
|
|
struct spam_synchdr *hdr; |
241 |
|
|
struct sockaddr_in addr; |
242 |
|
|
struct spam_synctlv_hdr *tlv; |
243 |
|
|
struct spam_synctlv_grey *sg; |
244 |
|
|
struct spam_synctlv_addr *sd; |
245 |
|
|
u_int8_t buf[SPAM_SYNC_MAXSIZE]; |
246 |
|
|
u_int8_t hmac[2][SPAM_SYNC_HMAC_LEN]; |
247 |
|
|
struct in_addr ip; |
248 |
|
|
char *from, *to, *helo; |
249 |
|
|
u_int8_t *p; |
250 |
|
|
socklen_t addr_len; |
251 |
|
|
ssize_t len; |
252 |
|
|
u_int hmac_len; |
253 |
|
|
u_int32_t expire; |
254 |
|
|
|
255 |
|
|
memset(&addr, 0, sizeof(addr)); |
256 |
|
|
memset(buf, 0, sizeof(buf)); |
257 |
|
|
|
258 |
|
|
addr_len = sizeof(addr); |
259 |
|
|
if ((len = recvfrom(syncfd, buf, sizeof(buf), 0, |
260 |
|
|
(struct sockaddr *)&addr, &addr_len)) < 1) |
261 |
|
|
return; |
262 |
|
|
if (addr.sin_addr.s_addr != htonl(INADDR_ANY) && |
263 |
|
|
bcmp(&sync_in.sin_addr, &addr.sin_addr, |
264 |
|
|
sizeof(addr.sin_addr)) == 0) |
265 |
|
|
return; |
266 |
|
|
|
267 |
|
|
/* Ignore invalid or truncated packets */ |
268 |
|
|
hdr = (struct spam_synchdr *)buf; |
269 |
|
|
if (len < sizeof(struct spam_synchdr) || |
270 |
|
|
hdr->sh_version != SPAM_SYNC_VERSION || |
271 |
|
|
hdr->sh_af != AF_INET || |
272 |
|
|
len < ntohs(hdr->sh_length)) |
273 |
|
|
goto trunc; |
274 |
|
|
len = ntohs(hdr->sh_length); |
275 |
|
|
|
276 |
|
|
/* Compute and validate HMAC */ |
277 |
|
|
memcpy(hmac[0], hdr->sh_hmac, SPAM_SYNC_HMAC_LEN); |
278 |
|
|
explicit_bzero(hdr->sh_hmac, SPAM_SYNC_HMAC_LEN); |
279 |
|
|
HMAC(EVP_sha1(), sync_key, strlen(sync_key), buf, len, |
280 |
|
|
hmac[1], &hmac_len); |
281 |
|
|
if (bcmp(hmac[0], hmac[1], SPAM_SYNC_HMAC_LEN) != 0) |
282 |
|
|
goto trunc; |
283 |
|
|
|
284 |
|
|
if (debug) |
285 |
|
|
fprintf(stderr, |
286 |
|
|
"%s(sync): received packet of %d bytes\n", |
287 |
|
|
inet_ntoa(addr.sin_addr), (int)len); |
288 |
|
|
|
289 |
|
|
p = (u_int8_t *)(hdr + 1); |
290 |
|
|
while (len) { |
291 |
|
|
tlv = (struct spam_synctlv_hdr *)p; |
292 |
|
|
|
293 |
|
|
if (len < sizeof(struct spam_synctlv_hdr) || |
294 |
|
|
len < ntohs(tlv->st_length)) |
295 |
|
|
goto trunc; |
296 |
|
|
|
297 |
|
|
switch (ntohs(tlv->st_type)) { |
298 |
|
|
case SPAM_SYNC_GREY: |
299 |
|
|
sg = (struct spam_synctlv_grey *)tlv; |
300 |
|
|
if ((sizeof(*sg) + |
301 |
|
|
ntohs(sg->sg_from_length) + |
302 |
|
|
ntohs(sg->sg_to_length) + |
303 |
|
|
ntohs(sg->sg_helo_length)) > |
304 |
|
|
ntohs(tlv->st_length)) |
305 |
|
|
goto trunc; |
306 |
|
|
|
307 |
|
|
ip.s_addr = sg->sg_ip; |
308 |
|
|
from = (char *)(sg + 1); |
309 |
|
|
to = from + ntohs(sg->sg_from_length); |
310 |
|
|
helo = to + ntohs(sg->sg_to_length); |
311 |
|
|
if (debug) { |
312 |
|
|
fprintf(stderr, "%s(sync): " |
313 |
|
|
"received grey entry ", |
314 |
|
|
inet_ntoa(addr.sin_addr)); |
315 |
|
|
fprintf(stderr, "helo %s ip %s " |
316 |
|
|
"from %s to %s\n", |
317 |
|
|
helo, inet_ntoa(ip), from, to); |
318 |
|
|
} |
319 |
|
|
if (greylist) { |
320 |
|
|
/* send this info to the greylister */ |
321 |
|
|
fprintf(grey, |
322 |
|
|
"SYNC\nHE:%s\nIP:%s\nFR:%s\nTO:%s\n", |
323 |
|
|
helo, inet_ntoa(ip), from, to); |
324 |
|
|
fflush(grey); |
325 |
|
|
} |
326 |
|
|
break; |
327 |
|
|
case SPAM_SYNC_WHITE: |
328 |
|
|
sd = (struct spam_synctlv_addr *)tlv; |
329 |
|
|
if (sizeof(*sd) != ntohs(tlv->st_length)) |
330 |
|
|
goto trunc; |
331 |
|
|
|
332 |
|
|
ip.s_addr = sd->sd_ip; |
333 |
|
|
expire = ntohl(sd->sd_expire); |
334 |
|
|
if (debug) { |
335 |
|
|
fprintf(stderr, "%s(sync): " |
336 |
|
|
"received white entry ", |
337 |
|
|
inet_ntoa(addr.sin_addr)); |
338 |
|
|
fprintf(stderr, "ip %s ", inet_ntoa(ip)); |
339 |
|
|
} |
340 |
|
|
if (greylist) { |
341 |
|
|
/* send this info to the greylister */ |
342 |
|
|
fprintf(grey, "WHITE:%s:", inet_ntoa(ip)); |
343 |
|
|
fprintf(grey, "%s:%u\n", |
344 |
|
|
inet_ntoa(addr.sin_addr), expire); |
345 |
|
|
fflush(grey); |
346 |
|
|
} |
347 |
|
|
break; |
348 |
|
|
case SPAM_SYNC_TRAPPED: |
349 |
|
|
sd = (struct spam_synctlv_addr *)tlv; |
350 |
|
|
if (sizeof(*sd) != ntohs(tlv->st_length)) |
351 |
|
|
goto trunc; |
352 |
|
|
|
353 |
|
|
ip.s_addr = sd->sd_ip; |
354 |
|
|
expire = ntohl(sd->sd_expire); |
355 |
|
|
if (debug) { |
356 |
|
|
fprintf(stderr, "%s(sync): " |
357 |
|
|
"received trapped entry ", |
358 |
|
|
inet_ntoa(addr.sin_addr)); |
359 |
|
|
fprintf(stderr, "ip %s ", inet_ntoa(ip)); |
360 |
|
|
} |
361 |
|
|
if (greylist) { |
362 |
|
|
/* send this info to the greylister */ |
363 |
|
|
fprintf(grey, "TRAP:%s:", inet_ntoa(ip)); |
364 |
|
|
fprintf(grey, "%s:%u\n", |
365 |
|
|
inet_ntoa(addr.sin_addr), expire); |
366 |
|
|
fflush(grey); |
367 |
|
|
} |
368 |
|
|
break; |
369 |
|
|
case SPAM_SYNC_END: |
370 |
|
|
goto done; |
371 |
|
|
default: |
372 |
|
|
printf("invalid type: %d\n", ntohs(tlv->st_type)); |
373 |
|
|
goto trunc; |
374 |
|
|
} |
375 |
|
|
len -= ntohs(tlv->st_length); |
376 |
|
|
p = ((u_int8_t *)tlv) + ntohs(tlv->st_length); |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
done: |
380 |
|
|
return; |
381 |
|
|
|
382 |
|
|
trunc: |
383 |
|
|
if (debug) |
384 |
|
|
fprintf(stderr, "%s(sync): truncated or invalid packet\n", |
385 |
|
|
inet_ntoa(addr.sin_addr)); |
386 |
|
|
} |
387 |
|
|
|
388 |
|
|
void |
389 |
|
|
sync_send(struct iovec *iov, int iovlen) |
390 |
|
|
{ |
391 |
|
|
struct sync_host *shost; |
392 |
|
|
struct msghdr msg; |
393 |
|
|
|
394 |
|
|
/* setup buffer */ |
395 |
|
|
memset(&msg, 0, sizeof(msg)); |
396 |
|
|
msg.msg_iov = iov; |
397 |
|
|
msg.msg_iovlen = iovlen; |
398 |
|
|
|
399 |
|
|
if (sendmcast) { |
400 |
|
|
if (debug) |
401 |
|
|
fprintf(stderr, "sending multicast sync message\n"); |
402 |
|
|
msg.msg_name = &sync_out; |
403 |
|
|
msg.msg_namelen = sizeof(sync_out); |
404 |
|
|
sendmsg(syncfd, &msg, 0); |
405 |
|
|
} |
406 |
|
|
|
407 |
|
|
LIST_FOREACH(shost, &sync_hosts, h_entry) { |
408 |
|
|
if (debug) |
409 |
|
|
fprintf(stderr, "sending sync message to %s (%s)\n", |
410 |
|
|
shost->h_name, inet_ntoa(shost->sh_addr.sin_addr)); |
411 |
|
|
msg.msg_name = &shost->sh_addr; |
412 |
|
|
msg.msg_namelen = sizeof(shost->sh_addr); |
413 |
|
|
sendmsg(syncfd, &msg, 0); |
414 |
|
|
} |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
void |
418 |
|
|
sync_update(time_t now, char *helo, char *ip, char *from, char *to) |
419 |
|
|
{ |
420 |
|
|
struct iovec iov[7]; |
421 |
|
|
struct spam_synchdr hdr; |
422 |
|
|
struct spam_synctlv_grey sg; |
423 |
|
|
struct spam_synctlv_hdr end; |
424 |
|
|
u_int16_t sglen, fromlen, tolen, helolen, padlen; |
425 |
|
|
char pad[SPAM_ALIGNBYTES]; |
426 |
|
|
int i = 0; |
427 |
|
|
HMAC_CTX ctx; |
428 |
|
|
u_int hmac_len; |
429 |
|
|
|
430 |
|
|
if (debug) |
431 |
|
|
fprintf(stderr, |
432 |
|
|
"sync grey update helo %s ip %s from %s to %s\n", |
433 |
|
|
helo, ip, from, to); |
434 |
|
|
|
435 |
|
|
memset(&hdr, 0, sizeof(hdr)); |
436 |
|
|
memset(&sg, 0, sizeof(sg)); |
437 |
|
|
memset(&pad, 0, sizeof(pad)); |
438 |
|
|
|
439 |
|
|
fromlen = strlen(from) + 1; |
440 |
|
|
tolen = strlen(to) + 1; |
441 |
|
|
helolen = strlen(helo) + 1; |
442 |
|
|
|
443 |
|
|
HMAC_CTX_init(&ctx); |
444 |
|
|
HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); |
445 |
|
|
|
446 |
|
|
sglen = sizeof(sg) + fromlen + tolen + helolen; |
447 |
|
|
padlen = SPAM_ALIGN(sglen) - sglen; |
448 |
|
|
|
449 |
|
|
/* Add SPAM sync packet header */ |
450 |
|
|
hdr.sh_version = SPAM_SYNC_VERSION; |
451 |
|
|
hdr.sh_af = AF_INET; |
452 |
|
|
hdr.sh_counter = htonl(sync_counter++); |
453 |
|
|
hdr.sh_length = htons(sizeof(hdr) + sglen + padlen + sizeof(end)); |
454 |
|
|
iov[i].iov_base = &hdr; |
455 |
|
|
iov[i].iov_len = sizeof(hdr); |
456 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
457 |
|
|
i++; |
458 |
|
|
|
459 |
|
|
/* Add single SPAM sync greylisting entry */ |
460 |
|
|
sg.sg_type = htons(SPAM_SYNC_GREY); |
461 |
|
|
sg.sg_length = htons(sglen + padlen); |
462 |
|
|
sg.sg_timestamp = htonl(now); |
463 |
|
|
sg.sg_ip = inet_addr(ip); |
464 |
|
|
sg.sg_from_length = htons(fromlen); |
465 |
|
|
sg.sg_to_length = htons(tolen); |
466 |
|
|
sg.sg_helo_length = htons(helolen); |
467 |
|
|
iov[i].iov_base = &sg; |
468 |
|
|
iov[i].iov_len = sizeof(sg); |
469 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
470 |
|
|
i++; |
471 |
|
|
|
472 |
|
|
iov[i].iov_base = from; |
473 |
|
|
iov[i].iov_len = fromlen; |
474 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
475 |
|
|
i++; |
476 |
|
|
|
477 |
|
|
iov[i].iov_base = to; |
478 |
|
|
iov[i].iov_len = tolen; |
479 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
480 |
|
|
i++; |
481 |
|
|
|
482 |
|
|
iov[i].iov_base = helo; |
483 |
|
|
iov[i].iov_len = helolen; |
484 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
485 |
|
|
i++; |
486 |
|
|
|
487 |
|
|
iov[i].iov_base = pad; |
488 |
|
|
iov[i].iov_len = padlen; |
489 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
490 |
|
|
i++; |
491 |
|
|
|
492 |
|
|
/* Add end marker */ |
493 |
|
|
end.st_type = htons(SPAM_SYNC_END); |
494 |
|
|
end.st_length = htons(sizeof(end)); |
495 |
|
|
iov[i].iov_base = &end; |
496 |
|
|
iov[i].iov_len = sizeof(end); |
497 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
498 |
|
|
i++; |
499 |
|
|
|
500 |
|
|
HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); |
501 |
|
|
|
502 |
|
|
/* Send message to the target hosts */ |
503 |
|
|
sync_send(iov, i); |
504 |
|
|
HMAC_CTX_cleanup(&ctx); |
505 |
|
|
} |
506 |
|
|
|
507 |
|
|
void |
508 |
|
|
sync_addr(time_t now, time_t expire, char *ip, u_int16_t type) |
509 |
|
|
{ |
510 |
|
|
struct iovec iov[3]; |
511 |
|
|
struct spam_synchdr hdr; |
512 |
|
|
struct spam_synctlv_addr sd; |
513 |
|
|
struct spam_synctlv_hdr end; |
514 |
|
|
int i = 0; |
515 |
|
|
HMAC_CTX ctx; |
516 |
|
|
u_int hmac_len; |
517 |
|
|
|
518 |
|
|
if (debug) |
519 |
|
|
fprintf(stderr, "sync %s %s\n", |
520 |
|
|
type == SPAM_SYNC_WHITE ? "white" : "trapped", ip); |
521 |
|
|
|
522 |
|
|
memset(&hdr, 0, sizeof(hdr)); |
523 |
|
|
memset(&sd, 0, sizeof(sd)); |
524 |
|
|
|
525 |
|
|
HMAC_CTX_init(&ctx); |
526 |
|
|
HMAC_Init(&ctx, sync_key, strlen(sync_key), EVP_sha1()); |
527 |
|
|
|
528 |
|
|
/* Add SPAM sync packet header */ |
529 |
|
|
hdr.sh_version = SPAM_SYNC_VERSION; |
530 |
|
|
hdr.sh_af = AF_INET; |
531 |
|
|
hdr.sh_counter = htonl(sync_counter++); |
532 |
|
|
hdr.sh_length = htons(sizeof(hdr) + sizeof(sd) + sizeof(end)); |
533 |
|
|
iov[i].iov_base = &hdr; |
534 |
|
|
iov[i].iov_len = sizeof(hdr); |
535 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
536 |
|
|
i++; |
537 |
|
|
|
538 |
|
|
/* Add single SPAM sync address entry */ |
539 |
|
|
sd.sd_type = htons(type); |
540 |
|
|
sd.sd_length = htons(sizeof(sd)); |
541 |
|
|
sd.sd_timestamp = htonl(now); |
542 |
|
|
sd.sd_expire = htonl(expire); |
543 |
|
|
sd.sd_ip = inet_addr(ip); |
544 |
|
|
iov[i].iov_base = &sd; |
545 |
|
|
iov[i].iov_len = sizeof(sd); |
546 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
547 |
|
|
i++; |
548 |
|
|
|
549 |
|
|
/* Add end marker */ |
550 |
|
|
end.st_type = htons(SPAM_SYNC_END); |
551 |
|
|
end.st_length = htons(sizeof(end)); |
552 |
|
|
iov[i].iov_base = &end; |
553 |
|
|
iov[i].iov_len = sizeof(end); |
554 |
|
|
HMAC_Update(&ctx, iov[i].iov_base, iov[i].iov_len); |
555 |
|
|
i++; |
556 |
|
|
|
557 |
|
|
HMAC_Final(&ctx, hdr.sh_hmac, &hmac_len); |
558 |
|
|
|
559 |
|
|
/* Send message to the target hosts */ |
560 |
|
|
sync_send(iov, i); |
561 |
|
|
HMAC_CTX_cleanup(&ctx); |
562 |
|
|
} |
563 |
|
|
|
564 |
|
|
void |
565 |
|
|
sync_white(time_t now, time_t expire, char *ip) |
566 |
|
|
{ |
567 |
|
|
sync_addr(now, expire, ip, SPAM_SYNC_WHITE); |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
void |
571 |
|
|
sync_trapped(time_t now, time_t expire, char *ip) |
572 |
|
|
{ |
573 |
|
|
sync_addr(now, expire, ip, SPAM_SYNC_TRAPPED); |
574 |
|
|
} |