comparison dccd/iflod.c @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:c7f6b056b673
1 /* Distributed Checksum Clearinghouse
2 *
3 * deal with incoming floods of checksums
4 *
5 * Copyright (c) 2008 by Rhyolite Software, LLC
6 *
7 * This agreement is not applicable to any entity which sells anti-spam
8 * solutions to others or provides an anti-spam solution as part of a
9 * security solution sold to other entities, or to a private network
10 * which employs the DCC or uses data provided by operation of the DCC
11 * but does not provide corresponding data to other users.
12 *
13 * Permission to use, copy, modify, and distribute this software without
14 * changes for any purpose with or without fee is hereby granted, provided
15 * that the above copyright notice and this permission notice appear in all
16 * copies and any distributed versions or copies are either unchanged
17 * or not called anything similar to "DCC" or "Distributed Checksum
18 * Clearinghouse".
19 *
20 * Parties not eligible to receive a license under this agreement can
21 * obtain a commercial license to use DCC by contacting Rhyolite Software
22 * at sales@rhyolite.com.
23 *
24 * A commercial license would be for Distributed Checksum and Reputation
25 * Clearinghouse software. That software includes additional features. This
26 * free license for Distributed ChecksumClearinghouse Software does not in any
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse
28 * software
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37 * SOFTWARE.
38 *
39 * Rhyolite Software DCC 1.3.103-1.249 $Revision$
40 */
41
42 #include "dccd_defs.h"
43 #include <sys/wait.h>
44
45
46 IFLODS iflods;
47
48 u_int complained_many_iflods;
49
50 time_t got_hosts;
51 pid_t resolve_hosts_pid = -1;
52
53 time_t iflods_ok_timer; /* incoming flooding ok since then */
54
55 int flod_trace_gen; /* unsuppress tracing */
56
57 static u_char iflod_write(IFLOD_INFO *, void *, int, const char *, u_char);
58
59
60 static DCC_TS future; /* timestamp sanity */
61
62
63
64 ID_MAP_RESULT
65 id_map(DCC_SRVR_ID srvr, const OFLOD_OPTS *opts)
66 {
67 int i;
68 ID_MAP_RESULT result;
69
70 /* apply the ***first*** server-ID map that matches, if any */
71 for (i = 0; i < opts->num_maps; ++i) {
72 if (opts->srvr_map[i].from_lo <= srvr
73 && opts->srvr_map[i].from_hi >= srvr) {
74 result = opts->srvr_map[i].result;
75 if (result == ID_MAP_SELF
76 && srvr == my_srvr_id)
77 return ID_MAP_NO;
78 return result;
79 }
80 }
81 return ID_MAP_NO;
82 }
83
84
85
86 static const char *
87 rem_str(const char *hostname, const DCC_SOCKU *su)
88 {
89 static int bufno;
90 static struct {
91 char str[90];
92 } bufs[4];
93 char *s;
94 char sustr[DCC_SU2STR_SIZE];
95 int i;
96
97 s = bufs[bufno].str;
98 bufno = (bufno+1) % DIM(bufs);
99
100 STRLCPY(s, hostname, sizeof(bufs[0].str));
101
102 if (su->sa.sa_family == AF_UNSPEC
103 && *DCC_SU_PORTP(su) == 0)
104 return s;
105
106 dcc_su2str2(sustr, sizeof(sustr), su);
107 if (strcmp(s, sustr)) {
108 STRLCAT(s, " ", sizeof(bufs[0].str));
109 STRLCAT(s, sustr, sizeof(bufs[0].str));
110 }
111 if (*DCC_SU_PORTP(su) != DCC_GREY2PORT(grey_on)) {
112 i = strlen(s);
113 snprintf(s+i, sizeof(bufs[0].str)-i,
114 ",%d", ntohs(*DCC_SU_PORTP(su)));
115 }
116 return s;
117 }
118
119
120
121 const char *
122 ifp_rem_str(const IFLOD_INFO *ifp)
123 {
124 if (!ifp)
125 return "(null ifp)";
126 return rem_str(ifp->rem_hostname, &ifp->rem_su);
127 }
128
129
130
131 const char *
132 ofp_rem_str(const OFLOD_INFO *ofp)
133 {
134 if (!ofp)
135 return "(null ofp)";
136 return rem_str(ofp->rem_hostname, &ofp->rem_su);
137 }
138
139
140
141 static const char *
142 rpt_id(const char *type, const DB_RCD* rcd,
143 const IFLOD_INFO *ifp)
144 {
145 static int bufno;
146 static struct {
147 char str[120];
148 } bufs[4];
149 char *s;
150 char id_buf[30];
151
152 s = bufs[bufno].str;
153 bufno = (bufno+1) % DIM(bufs);
154
155 snprintf(s, sizeof(bufs[0].str), "%s%s %s ID=%s %s%s",
156 type ? "flooded " : "",
157 type ? type : "",
158 ts2str_err(&rcd->ts),
159 id2str(id_buf, sizeof(id_buf), rcd->srvr_id_auth),
160 ifp ? "from " : "",
161 ifp ? ifp_rem_str(ifp) : "");
162 return s;
163 }
164
165
166
167 void PATTRIB(2,3)
168 flod_cnterr(const FLOD_LIMCNT *lc, const char *p, ...)
169 {
170 char buf[200];
171 va_list args;
172
173 va_start(args, p);
174 if (lc->cur < lc->lim + FLOD_LIM_COMPLAINTS) {
175 dcc_verror_msg(p, args);
176 } else {
177 vsnprintf(buf, sizeof(FLOD_EMSG), p, args);
178 dcc_error_msg("%s; stop complaints", buf);
179 }
180 va_end(args);
181 }
182
183
184
185 static void
186 date_err_msg(FLOD_EMSG out, int len, const char *in)
187 {
188 memcpy(out, in, len);
189 if (len >= ISZ(FLOD_EMSG)-LITZ(" at hh:mm:ss")-1) {
190 out[len] = '\0';
191 } else {
192 dcc_time2str(&out[len], ISZ(FLOD_EMSG)-len, " at %T",
193 db_time.tv_sec);
194 }
195 }
196
197
198
199 /* remove extra quotes and strings from a message to or from a peer */
200 static void
201 trim_err_msg(FLOD_EMSG out, const FLOD_EMSG in)
202 {
203 char *q1, *q2;
204 int len;
205
206 q1 = strchr(in, '\'');
207 if (q1) {
208 q2 = strrchr(++q1, '\'');
209 if (q2) {
210 len = q2-q1;
211 if (len > LITZ(DCC_FLOD_OK_STR)
212 && !LITCMP(q1, DCC_FLOD_OK_STR)) {
213 len -= LITZ(DCC_FLOD_OK_STR);
214 q1 += LITZ(DCC_FLOD_OK_STR);
215 }
216 date_err_msg(out, len, q1);
217 return;
218 }
219 }
220 date_err_msg(out, strlen(in), in);
221 }
222
223
224
225 /* report a flooding error */
226 void PATTRIB(4,5)
227 rpt_err(OFLOD_INFO *ofp,
228 u_char trace, /* 0=error, 1=trace, 2=no dup trace */
229 u_char in, /* 0=output 1=input */
230 const char *p, ...)
231 {
232 FLOD_MMAP *mp;
233 LAST_ERROR *ep;
234 FLOD_EMSG tmp, trimmed;
235 va_list args;
236
237 va_start(args, p);
238 vsnprintf(tmp, sizeof(FLOD_EMSG), p, args);
239 va_end(args);
240
241 mp = ofp ? ofp->mp : 0;
242
243 if (trace != 0) {
244 if (!mp) {
245 TMSG_FLOD(ofp, tmp);
246 return;
247 }
248
249 trim_err_msg(trimmed, tmp);
250 ep = in ? &mp->iflod_err : &mp->oflod_err;
251 if (TMSG_FB(ofp)
252 && (trace < 2
253 || strcmp(trimmed, ep->trace_msg)
254 || ep->trace_gen != flod_trace_gen)) {
255 /* suppress some duplicate flooding messages */
256 dcc_trace_msg(tmp);
257 ep->trace_gen = flod_trace_gen;
258 }
259 strncpy(ep->trace_msg, trimmed, sizeof(ep->trace_msg));
260 ep->complained = 0;
261
262 } else {
263 if (!mp) {
264 dcc_error_msg(tmp);
265 return;
266 }
267
268 dcc_error_msg(tmp);
269
270 ep = in ? &mp->iflod_err : &mp->oflod_err;
271 trim_err_msg(ep->msg, tmp);
272 ep->trace_msg[0] = '\0';
273 ep->complained = 0;
274 }
275 }
276
277
278
279 u_char
280 set_flod_socket(OFLOD_INFO *ofp, u_char in, int s,
281 const char *hostname, const DCC_SOCKU *sup)
282 {
283 #if IP_TOS
284 static u_char tos_ok = 1;
285 #endif
286 int on;
287
288 if (0 > fcntl(s, F_SETFD, FD_CLOEXEC))
289 rpt_err(ofp, 0, in, "fcntl(%s, F_SETFD, FD_CLOEXEC): %s",
290 rem_str(hostname, sup), ERROR_STR());
291
292 if (-1 == fcntl(s, F_SETFL,
293 fcntl(s, F_GETFL, 0) | O_NONBLOCK)) {
294 rpt_err(ofp, 0, in, "fcntl(%s, O_NONBLOCK): %s",
295 rem_str(hostname, sup), ERROR_STR());
296 return 0;
297 }
298
299 on = 1;
300 if (0 > setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
301 &on, sizeof(on)))
302 rpt_err(ofp, 0, in, "setsockopt(flod %s, SO_KEEPALIVE): %s",
303 rem_str(hostname, sup), ERROR_STR());
304
305 if (in) {
306 /* Ensure that we have enough socket buffer space to send
307 * complaints about the input flood. Normally little or
308 * nothing is sent upstream, but bad clocks or other
309 * problems can cause many complaints. */
310 if (0 > setsockopt(s, SOL_SOCKET, SO_SNDBUF,
311 &srvr_rcvbuf, sizeof(srvr_rcvbuf)))
312 rpt_err(ofp, 0, in, "setsockopt(%s, SO_SNDBUF): %s",
313 rem_str(hostname, sup), ERROR_STR());
314 }
315
316 #ifdef IP_TOS
317 /* It would be nice and clean to use netinet/ip.h for the definition
318 * of IPTOS_THROUGHPUT. However, it is hard to use netinet/ip.h
319 * portably because in_sysm.h is required for n_long on some
320 * systems and not others. A bunch of messy ./configure fiddling
321 * might patch that hassle, but the bit really ought to be the same
322 * as the old 0x08 in the IPv4 header. */
323 if (sup->sa.sa_family == AF_INET
324 && tos_ok) {
325 on = 0x08; /* IPTOS_THROUGHPUT */
326 if (0 > setsockopt(s, IPPROTO_IP, IP_TOS, &on, sizeof(on))) {
327 rpt_err(ofp, 0, in,
328 "setsockopt(IP_TOS, IPTOS_THROUGHPUT, %s): %s",
329 rem_str(hostname, sup), ERROR_STR());
330 tos_ok = 0;
331 }
332 }
333 #endif
334
335 return 1;
336 }
337
338
339
340 /* see if the host name resolution process is still running */
341 u_char /* 1=not running 0=please wait */
342 flod_names_resolve_ck(void)
343 {
344 int status;
345
346 if (resolve_hosts_pid < 0)
347 return 1;
348
349 if (resolve_hosts_pid == waitpid(resolve_hosts_pid, &status, WNOHANG)) {
350 resolve_hosts_pid = -1;
351 return 1;
352 }
353
354 RUSH_NEXT_FLODS_CK();
355 return 0;
356 }
357
358
359
360 static void
361 flod_names_resolve(void)
362 {
363 FLOD_MMAP *mp;
364 u_char ipv6, ok;
365 const DCC_SOCKU *sup;
366
367 for (mp = flod_mmaps->mmaps; mp <= LAST(flod_mmaps->mmaps); ++mp) {
368 if (mp->rem_hostname[0] == '\0'
369 || (mp->flags & FLODMAP_FG_PASSIVE))
370 continue;
371 ipv6 = ((mp->flags & FLODMAP_FG_IPv4) ? 0
372 : (mp->flags & FLODMAP_FG_IPv6) ? 1
373 : use_ipv6 ? 2 : 0);
374 dcc_host_lock();
375 if (mp->flags & FLODMAP_FG_SOCKS)
376 ok = dcc_get_host_SOCKS(mp->rem_hostname, ipv6,
377 &mp->host_error);
378 else
379 ok = dcc_get_host(mp->rem_hostname, ipv6,
380 &mp->host_error);
381 if (!ok) {
382 TMSG2(FLOD, "failed to resolve %s: %s",
383 mp->rem_hostname, DCC_HSTRERROR(mp->host_error));
384 } else {
385 for (sup = dcc_hostaddrs;
386 sup < dcc_hostaddrs_end;
387 ++sup) {
388 if ((ipv6 == 0
389 && sup->sa.sa_family != AF_INET)
390 || (ipv6 == 1
391 && sup->sa.sa_family != AF_INET6))
392 continue;
393 mp->rem_su = *sup;
394 *DCC_SU_PORTP(&mp->rem_su) = mp->rem_port;
395 }
396 }
397 dcc_host_unlock();
398 }
399 }
400
401
402
403 /* start a process to wait for the domain name system or other
404 * hostname system to get the IP addresses of our flooding peers */
405 u_char /* 1=finished 0=please wait */
406 flod_names_resolve_start(void)
407 {
408 FLOD_MMAP *mp;
409
410 if (!flod_mmaps)
411 return 0;
412
413 /* wait for background job to finish */
414 if (!flod_names_resolve_ck())
415 return 0;
416
417 /* we're finished if we have recent address for all of the names */
418 if (!DB_IS_TIME(got_hosts, FLOD_NAMES_RESOLVE_SECS))
419 return 1;
420
421 got_hosts = db_time.tv_sec + FLOD_NAMES_RESOLVE_SECS;
422 for (mp = flod_mmaps->mmaps; mp <= LAST(flod_mmaps->mmaps); ++mp) {
423 mp->rem_su.sa.sa_family = AF_UNSPEC;
424 mp->host_error = 0;
425 }
426 flod_mmap_sync(0, 1);
427
428 if (!background) {
429 TMSG(FLOD, "resolving hostnames in the foreground");
430 flod_names_resolve();
431 return 1;
432 }
433
434 resolve_hosts_pid = fork();
435 if (resolve_hosts_pid > 0) {
436 /* check again soon */
437 RUSH_NEXT_FLODS_CK();
438 return 0;
439 }
440
441 if (resolve_hosts_pid == -1) {
442 dcc_error_msg("fork(flood names resolve start): %s;"
443 " fall back to foreground resolving",
444 ERROR_STR());
445 flod_names_resolve();
446 return 1;
447 }
448
449 TMSG(FLOD, "resolving hostnames started");
450 /* close files and sockets to avoid interfering with parent */
451 db_close(-1);
452 after_fork();
453
454 flod_names_resolve();
455
456 TMSG(FLOD, "resolving hostnames finished");
457
458 exit(0);
459 }
460
461
462
463 static void
464 iflod_clear(IFLOD_INFO *ifp,
465 u_char fail) /* 1=problems so delay restart */
466 {
467 OFLOD_INFO *ofp;
468 FLOD_MMAP *mp;
469
470 ofp = ifp->ofp;
471 if (fail && ofp != 0) {
472 mp = ofp->mp;
473 if (mp->itimers.retry_secs < FLOD_RETRY_SECS)
474 mp->itimers.retry_secs = FLOD_RETRY_SECS;
475 mp->itimers.retry = db_time.tv_sec + mp->itimers.retry_secs;
476 if ((mp->flags & FLODMAP_FG_ACT) != 0)
477 TMSG3_FLOD(ofp,
478 "postpone restarting %s flood from"
479 " %s for %d seconds",
480 (mp->flags & FLODMAP_FG_SOCKS)
481 ? "SOCKS"
482 : (mp->flags & FLODMAP_FG_NAT)
483 ? "NAT"
484 : "auto-NAT",
485 ofp_rem_str(ofp), mp->itimers.retry_secs);
486 }
487
488 /* do not close the socket here, because it may be a passive outgoing
489 * stream that is being converted */
490 if (ifp->soc >= 0)
491 --iflods.open;
492
493 memset(ifp, 0, sizeof(*ifp));
494 ifp->soc = -1;
495
496 if (iflods.open == 0
497 && oflods.open == 0
498 && flods_st != FLODS_ST_ON)
499 oflods_clear();
500 }
501
502
503
504 void PATTRIB(5,6)
505 iflod_close(IFLOD_INFO *ifp,
506 u_char fail, /* 1=already sick; more is no problem */
507 u_char complain, /* 1=error not just trace message */
508 u_char send_reason,
509 const char *pat, ...)
510 {
511 struct {
512 DCC_FLOD_POS last_pos;
513 DCC_FLOD_RESP e;
514 u_char null; /* to eat '\0' for e.msg */
515 } resp;
516 void *wp;
517 va_list args;
518 OFLOD_INFO *ofp;
519 struct linger nowait;
520 int wlen;
521
522 ofp = ifp->ofp;
523
524 db_ptr2flod_pos(resp.e.end.pos, DCC_FLOD_POS_END);
525 va_start(args, pat);
526 /* Throw away the last byte of resp.e.end.msg because the too smart
527 * by half gcc Fortify nonsense won't allow ISZ(resp.e.end.msg)+1.
528 * That put the would the unwanted '\0' from vsnprintf() into
529 * resp.null*/
530 wlen = vsnprintf(resp.e.end.msg, ISZ(resp.e.end.msg), pat, args);
531 va_end(args);
532 if (wlen > ISZ(resp.e.end.msg))
533 wlen = ISZ(resp.e.end.msg);
534 wlen += FLOD_END_OVHD;
535
536 /* If useful, prefix our final message with our final position
537 * The peer will see our position and final operation as two
538 * separate responses. */
539 if (memcmp(ifp->pos, ifp->pos_sent, ISZ(ifp->pos))) {
540 memcpy(resp.last_pos, ifp->pos, ISZ(resp.last_pos));
541 wlen += ISZ(resp.last_pos);
542 wp = &resp.last_pos;
543 } else {
544 wp = &resp.e;
545 }
546
547 if (send_reason) {
548 rpt_err(ofp, !complain, 1,
549 "stop incoming flood; %ssend '%s' to %s",
550 fail ? "error, " : "",
551 resp.e.end.msg,
552 ifp_rem_str(ifp));
553
554 /* send the final status report to the sending flooder */
555 iflod_write(ifp, wp, wlen, "stop incoming flood", fail ? 2 : 1);
556 } else {
557 rpt_err(ofp, !complain, 1,
558 "stop incoming flood; %s'%s'",
559 fail ? "error, " : "", resp.e.end.msg);
560 }
561
562 if (ifp->soc >= 0) {
563 if (stopint
564 && !(ifp->flags & IFLOD_FG_FAST_LINGER)) {
565 ifp->flags |= IFLOD_FG_FAST_LINGER;
566 nowait.l_onoff = 1;
567 nowait.l_linger = SHUTDOWN_DELAY;
568 if (0 > setsockopt(ifp->soc, SOL_SOCKET, SO_LINGER,
569 &nowait, sizeof(nowait))
570 && !fail)
571 dcc_error_msg("setsockopt(SO_LINGER %s): %s",
572 ifp_rem_str(ifp), ERROR_STR());
573 }
574
575 if (0 > close(ifp->soc)
576 && !fail) {
577 if (errno == ECONNRESET)
578 TMSG2_FLOD(ofp, "close(flood from %s): %s",
579 ifp_rem_str(ifp), ERROR_STR());
580 else
581 dcc_error_msg("close(flood from %s): %s",
582 ifp_rem_str(ifp), ERROR_STR());
583 }
584 }
585
586 /* if this was not a new duplicate connection being discarded,
587 * break the association with the outgoing stream */
588 if (ofp != 0 && ofp->ifp == ifp) {
589 save_flod_cnts(ofp);
590 ofp->ifp = 0;
591 }
592
593 iflod_clear(ifp, fail);
594 }
595
596
597
598 /* can close the incoming flood and so clear things */
599 static u_char /* 0=failed & should be or is closed */
600 iflod_write(IFLOD_INFO *ifp,
601 void *buf, int buf_len,
602 const char *type, /* string describing operation */
603 u_char close_it) /* 0=iflod_close() on error, */
604 { /* 1=complain, 2=ignore error */
605 int i;
606
607 if (!(ifp->flags & IFLOD_FG_CONNECTED))
608 return 1;
609
610 if (ifp->ofp
611 && (ifp->ofp->o_opts.flags & FLOD_OPT_SOCKS)) {
612 i = Rsend(ifp->soc, buf, buf_len, 0);
613 } else {
614 /* If we don't know the corresponding output stream because we
615 * have not yet seen any authentication, we at least know the
616 * connection did not involve SOCKS because we did not
617 * originate it. */
618 i = send(ifp->soc, buf, buf_len, 0);
619 }
620 if (i == buf_len) {
621 ifp->iflod_alive = db_time.tv_sec;
622 return 1;
623 }
624
625 if (i < 0) {
626 if (close_it == 0) {
627 iflod_close(ifp, 1, 0, 0, "send(%s %s): %s",
628 type, ifp_rem_str(ifp), ERROR_STR());
629 } else if (close_it == 1) {
630 dcc_error_msg("send(%s %s): %s",
631 type, ifp_rem_str(ifp), ERROR_STR());
632 }
633 } else {
634 if (close_it == 0) {
635 iflod_close(ifp, 1, 0, 0, "send(%s %s)=%d not %d",
636 type, ifp_rem_str(ifp), i, buf_len);
637 } else if (close_it == 1) {
638 dcc_error_msg("send(%s %s)=%d not %d",
639 type, ifp_rem_str(ifp), i, buf_len);
640 }
641 }
642 return 0;
643 }
644
645
646
647 /* send our current position to the peer
648 * the peer must be well known so that ifp->ofp->mp!=0, usually
649 * because (ifp->flags & IFLOD_FG_VERS_CK)
650 * can close the incoming flood and so clear things */
651 int /* -1=fail 0=nothing to send, 1=sent */
652 iflod_send_pos(IFLOD_INFO *ifp,
653 u_char force) /* say just anything */
654 {
655 DCC_FLOD_POS req;
656 OFLOD_INFO *ofp;
657 FLOD_MMAP *mp;
658
659 ofp = ifp->ofp;
660 mp = ofp->mp;
661
662 /* ask peer to start over if our database has been cleared */
663 if (mp->flags & FLODMAP_FG_FFWD_IN) {
664 mp->flags &= ~(FLODMAP_FG_FFWD_IN
665 | FLODMAP_FG_NEED_REWIND);
666 memcpy(ifp->pos_sent, ifp->pos, sizeof(ifp->pos_sent));
667 db_ptr2flod_pos(req, DCC_FLOD_POS_FFWD_IN);
668 dcc_trace_msg("ask %s to FFWD flood to us",
669 ifp_rem_str(ifp));
670 if (!iflod_write(ifp, req, sizeof(req), "ffwd request", 0))
671 return -1;
672 return 1;
673 }
674 if (mp->flags & FLODMAP_FG_NEED_REWIND) {
675 mp->flags &= ~FLODMAP_FG_NEED_REWIND;
676 memcpy(ifp->pos_sent, ifp->pos, sizeof(ifp->pos_sent));
677 db_ptr2flod_pos(req, DCC_FLOD_POS_REWIND);
678 dcc_trace_msg("ask %s to rewind flood to us",
679 ifp_rem_str(ifp));
680 if (!iflod_write(ifp, req, sizeof(req), "rewind request", 0))
681 return -1;
682 return 1;
683 }
684
685 if ((force && flod_pos2db_ptr(ifp->pos) >= DCC_FLOD_POS_MIN)
686 || memcmp(ifp->pos_sent, ifp->pos, sizeof(ifp->pos_sent))) {
687 memcpy(ifp->pos_sent, ifp->pos, sizeof(ifp->pos_sent));
688 if (!iflod_write(ifp, ifp->pos_sent, sizeof(ifp->pos_sent),
689 "confirmed pos", 0))
690 return -1;
691
692 /* reset the no-connection-from-peer complaint delay */
693 mp->itimers.msg_secs = FLOD_IN_COMPLAIN1;
694 mp->itimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN1;
695
696 /* things are going well, so forget old input complaints */
697 if (!(mp->flags & FLODMAP_FG_IN_SRVR)) {
698 mp->iflod_err.msg[0] = '\0';
699 mp->iflod_err.trace_msg[0] = '\0';
700 }
701
702 /* limit the backoff for outgoing connection attempts
703 * while the incoming connection is working */
704 DB_ADJ_TIMER(&mp->otimers.retry, &mp->otimers.retry_secs,
705 FLOD_RETRY_SECS);
706
707 return 1;
708 }
709
710 /* Say just anything if we are doing a keepalive probe before
711 * any checksums have been sent by the peer and so before we
712 * have a position to confirm. */
713 if (force) {
714 DCC_FLOD_RESP buf;
715
716 db_ptr2flod_pos(buf.note.op, DCC_FLOD_POS_NOTE);
717 strcpy(buf.note.str, "are you there?");
718 buf.note.len = sizeof("are you there?") + FLOD_NOTE_OVHD;
719 TMSG1_FLOD(ofp, "flood note to %s: \"are you there?\"",
720 ifp_rem_str(ifp));
721 if (!iflod_write(ifp, &buf.note, buf.note.len, buf.note.str, 0))
722 return -1;
723 return 1;
724 }
725
726 return 0;
727 }
728
729
730
731 void
732 iflod_listen_close(SRVR_SOC *sp)
733 {
734 if (sp->listen < 0)
735 return;
736
737 TMSG1(FLOD, "stop flood listening on %s", dcc_su2str_err(&sp->su));
738 if (0 > close(sp->listen))
739 TMSG2(FLOD, "close(flood listen on %s): %s",
740 dcc_su2str_err(&sp->su), ERROR_STR());
741 sp->listen = -1;
742 }
743
744
745
746 /* send stop requests to DCC servers flooding to us
747 * can close the incoming flood and so clear things */
748 void
749 iflods_stop(const char *reason,
750 u_char force) /* 1=now */
751 {
752 SRVR_SOC *sp;
753 IFLOD_INFO *ifp;
754 DCC_FLOD_POS end_req;
755
756 /* stop listening for new connections */
757 for (sp = srvr_socs; sp; sp = sp->fwd) {
758 iflod_listen_close(sp);
759 }
760
761 for (ifp = iflods.infos; ifp <= LAST(iflods.infos); ++ifp) {
762 if (ifp->soc < 0)
763 continue;
764
765 /* start shutting down each real, still alive connection */
766 if (!(ifp->flags & IFLOD_FG_END_REQ)
767 && (ifp->flags & IFLOD_FG_VERS_CK)) {
768 if (!reason || !*reason)
769 rpt_err(ifp->ofp, 1, 1,
770 "flood from %s stopping",
771 ifp_rem_str(ifp));
772 else
773 rpt_err(ifp->ofp, 1, 1,
774 "flood from %s stopping: '%s'",
775 ifp_rem_str(ifp), reason);
776
777 /* send any delay position and then a stop request */
778 if (0 <= iflod_send_pos(ifp, 0)) {
779 db_ptr2flod_pos(end_req, DCC_FLOD_POS_END_REQ);
780 iflod_write(ifp, end_req, sizeof(end_req),
781 "flood stop req", 0);
782 ifp->flags |= IFLOD_FG_END_REQ;
783 }
784
785 /* done if the socket died */
786 if (ifp->soc < 0)
787 continue;
788 }
789
790 /* break the connection if forced or never authenticated */
791 if (force || !(ifp->flags & IFLOD_FG_VERS_CK)) {
792 if (!reason || !*reason)
793 iflod_close(ifp, 1, 0, 1,
794 "flooding off at %s",
795 our_hostname);
796 else
797 iflod_close(ifp, 1, 0, 1,
798 "flooding off at %s; %s",
799 our_hostname, reason);
800 continue;
801 }
802
803 /* break the conneciton if the peer is too slow */
804 if ((ifp->flags & IFLOD_FG_END_REQ)
805 && IFP_DEAD(ifp, stopint
806 ? SHUTDOWN_DELAY : KEEPALIVE_IN_STOP)) {
807 if (!reason || !*reason)
808 iflod_close(ifp, 1, 0, 1,
809 DCC_FLOD_OK_STR" force close from"
810 " %s",
811 ifp_rem_str(ifp));
812 else
813 iflod_close(ifp, 1, 0, 1,
814 DCC_FLOD_OK_STR" force close from"
815 " %s; %s",
816 ifp_rem_str(ifp), reason);
817 continue;
818 }
819 }
820 }
821
822
823
824 /* start receiving checksums from another DCC server */
825 void
826 iflod_start(SRVR_SOC *sp)
827 {
828 IFLOD_INFO *ifp;
829 DCC_SOCKLEN_T l;
830 struct in6_addr peer_addr;
831 int count;
832 const struct in6_addr *cap;
833 RL *rl;
834
835 /* accept all waiting connections to avoid starving any */
836 for (count = 0; count <= DCCD_MAX_FLOODS; ++count) {
837 /* find a free input flooding slot */
838 for (ifp = iflods.infos; ifp->soc >= 0; ++ifp) {
839 if (ifp > LAST(iflods.infos)) {
840 if (!(complained_many_iflods++))
841 dcc_error_msg("too many floods");
842 goto again;
843 }
844 }
845
846 l = sizeof(ifp->rem_su);
847 ifp->soc = accept(sp->listen, &ifp->rem_su.sa, &l);
848 if (ifp->soc < 0) {
849 if (!DCC_BLOCK_ERROR() || count == 0)
850 dcc_error_msg("accept(flood): %s", ERROR_STR());
851 return;
852 }
853
854 /* use the IP address as the host name until we know which
855 * peer it is */
856 dcc_su2str2(ifp->rem_hostname, sizeof(ifp->rem_hostname),
857 &ifp->rem_su);
858 if (!set_flod_socket(0, 1, ifp->soc, ifp->rem_hostname,
859 &ifp->rem_su)) {
860 close(ifp->soc);
861 ifp->soc = -1;
862 continue;
863 }
864
865 /* quietly forget this peer if it is blacklisted */
866 if (ifp->rem_su.sa.sa_family == AF_INET6) {
867 cap = &ifp->rem_su.ipv6.sin6_addr;
868 } else {
869 dcc_ipv4toipv6(&peer_addr, ifp->rem_su.ipv4.sin_addr);
870 cap = &peer_addr;
871 }
872 rl = 0;
873 if (ck_ip_bl(&rl, DCC_ID_SRVR_ROGUE, cap)) {
874 char buf[120];
875 int len;
876
877 rl_inc(rl, &rl_anon_rate);
878 len = snprintf(buf, sizeof(buf)-1,
879 "rejected blacklisted flood from %s",
880 ifp_rem_str(ifp));
881 if (len > ISZ(buf))
882 len = sizeof(buf);
883 if ((rl->d.flags & RL_FG_TRACE)
884 || (dccd_tracemask & DCC_TRACE_FLOD_BIT))
885 dcc_trace_msg(buf);
886 buf[len++] = '\n';
887 send(ifp->soc, buf, len, 0);
888 close(ifp->soc);
889 ifp->soc = -1;
890 continue;
891 }
892
893 /* reset timer that delays responses to clients while flooding
894 * is stopped */
895 if (++iflods.open == 1)
896 iflods_ok_timer = db_time.tv_sec + IFLODS_OK_SECS;
897
898 ifp->flags |= IFLOD_FG_CONNECTED;
899 ifp->iflod_alive = db_time.tv_sec;
900
901 TMSG1(FLOD, "start flood from %s", ifp_rem_str(ifp));
902 again:;
903 }
904 }
905
906
907
908 static void
909 iflod_socks_backoff(OFLOD_INFO *ofp)
910 {
911 FLOD_MMAP *mp;
912
913 mp = ofp->mp;
914 mp->itimers.retry_secs *= 2;
915 if (mp->itimers.retry_secs > FLOD_MAX_RETRY_SECS)
916 mp->itimers.retry_secs = FLOD_MAX_RETRY_SECS;
917 else if (mp->itimers.retry_secs < FLOD_RETRY_SECS)
918 mp->itimers.retry_secs = FLOD_RETRY_SECS;
919 }
920
921
922
923 /* Start an incoming SOCKS flood by connecting to the other system.
924 * We will eventually turn the connection around and pretend that
925 * the other system initiated the TCP connection.
926 * This can close the flood and so clear things */
927 static int /* -1=failure, 0=not yet, 1=done */
928 iflod_socks_connect(IFLOD_INFO *ifp)
929 {
930 OFLOD_INFO *ofp;
931 DCC_SRVR_ID id;
932 DCC_FLOD_VERSION_HDR buf;
933 DCC_FNM_LNO_BUF fnm_buf;
934 const char *emsg;
935 int i;
936
937 ofp = ifp->ofp;
938
939 memset(&buf, 0, sizeof(buf));
940 strcpy(buf.body.str, version_str(ofp));
941 id = htons(my_srvr_id);
942 memcpy(buf.body.sender_srvr_id, &id, sizeof(buf.body.sender_srvr_id));
943 buf.body.turn = 1;
944 emsg = flod_sign(ofp, 1, &buf, sizeof(buf));
945 if (emsg) {
946 iflod_socks_backoff(ofp);
947 iflod_close(ifp, 1, 1, 1, "%s %d%s",
948 emsg, ofp->out_passwd_id,
949 fnm_lno(&fnm_buf, flod_path, ofp->lno));
950 return -1;
951 }
952
953 if (ofp->o_opts.flags & FLOD_OPT_SOCKS) {
954 i = Rconnect(ifp->soc, &ifp->rem_su.sa,
955 DCC_SU_LEN(&ifp->rem_su));
956 } else {
957 /* must be NAT or assumed NAT */
958 i = connect(ifp->soc, &ifp->rem_su.sa,
959 DCC_SU_LEN(&ifp->rem_su));
960 }
961 if (0 > i && errno != EISCONN) {
962 if (errno == EAGAIN
963 || errno == EINPROGRESS
964 || errno == EALREADY) {
965 rpt_err(ofp, 1, 0, "starting flood from %s",
966 ifp_rem_str(ifp));
967 return 0;
968 }
969
970 /* it is lame to only trace instead of reporting EINVAL as
971 * an error, but several UNIX-like systems return EINVAL for
972 * the second connect() after a Unreachable ICMP message
973 * or after a timeout */
974 rpt_err(ofp,
975 (errno == EINVAL || errno == ECONNABORTED
976 || errno == ECONNRESET || errno == ETIMEDOUT
977 || errno == ECONNREFUSED),
978 1, "connect(SOCKS FLOD %s): %s",
979 ifp_rem_str(ifp),
980 errno == EINVAL
981 ? "likely connection refused or local firewall"
982 : ERROR_STR());
983 close(ifp->soc);
984 iflod_socks_backoff(ofp);
985 iflod_clear(ifp, 1);
986
987 return -1;
988 }
989
990 ifp->flags |= (IFLOD_FG_CONNECTED | IFLOD_FG_CLIENT);
991
992 rpt_err(ofp, 1, 1, "starting SOCKS from %s", ifp_rem_str(ifp));
993
994 /* After the SOCKS incoming flood socket is connected,
995 * send our authentication to convince the peer to send its
996 * authentication and then its checksums. */
997 if (!iflod_write(ifp, &buf, sizeof(buf),
998 "flood SOCKS authentication", 0))
999 return -1;
1000 return 1;
1001 }
1002
1003
1004
1005 /* Request the start of an input flood via SOCKS if it is not already flowing,
1006 * by connecting to the remote system.
1007 * This can close the flood and so clear things */
1008 void
1009 iflod_socks_start(OFLOD_INFO *ofp)
1010 {
1011 DCC_FNM_LNO_BUF fnm_buf;
1012 IFLOD_INFO *ifp, *ifp1;
1013
1014 /* do nothing if it is already running or is not using SOCKS */
1015 if (ofp->ifp
1016 || (ofp->mp->flags & (FLODMAP_FG_SOCKS | FLODMAP_FG_NAT)) == 0
1017 || IFLOD_OPT_OFF_ROGUE(ofp))
1018 return;
1019 if (!DB_IS_TIME(ofp->mp->itimers.retry, ofp->mp->itimers.retry_secs))
1020 return;
1021
1022 /* look for a free slot or an existing slot for the incoming flood */
1023 ifp = 0;
1024 for (ifp1 = iflods.infos; ifp1 <= LAST(iflods.infos); ++ifp1) {
1025 if (ifp1->soc < 0) {
1026 if (!ifp)
1027 ifp = ifp1;
1028 }
1029 /* there is nothing to do if it already exists */
1030 if (ifp1->ofp == ofp)
1031 return;
1032 }
1033 if (!ifp) {
1034 rpt_err(ofp, ++complained_many_iflods == 1 ? 0 : 2, 1,
1035 "too many incoming floods to start SOCKS from %s",
1036 ofp->rem_hostname);
1037 iflod_socks_backoff(ofp);
1038 return;
1039 }
1040
1041 if (!flod_names_resolve_start())
1042 return; /* wait for name resolution */
1043 if (ofp->mp->rem_su.sa.sa_family == AF_UNSPEC) {
1044 rpt_err(ofp, 0, 1, "SOCKS flood peer name %s: %s%s",
1045 ofp->rem_hostname, DCC_HSTRERROR(ofp->mp->host_error),
1046 fnm_lno(&fnm_buf, flod_path, ofp->lno));
1047 iflod_socks_backoff(ofp);
1048 return;
1049 }
1050 if (!LITCMP(ofp->mp->oflod_err.msg, "SOCKS flood peer name "))
1051 ofp->mp->oflod_err.msg[0] = '\0';
1052
1053 ifp->ofp = ofp;
1054 ifp->rem_su = ofp->rem_su = ofp->mp->rem_su;
1055 STRLCPY(ifp->rem_hostname, ofp->rem_hostname,
1056 sizeof(ifp->rem_hostname));
1057
1058 ifp->soc = socket(ifp->rem_su.sa.sa_family, SOCK_STREAM, 0);
1059 if (ifp->soc < 0) {
1060 rpt_err(ofp, 0, 1, "socket(SOCKS flood %s): %s",
1061 ifp_rem_str(ifp), ERROR_STR());
1062 iflod_socks_backoff(ofp);
1063 return;
1064 }
1065
1066 if (!set_flod_socket(ofp, 1, ifp->soc,
1067 ifp->rem_hostname, &ifp->rem_su)) {
1068 close(ifp->soc);
1069 ifp->soc = -1;
1070 iflod_socks_backoff(ofp);
1071 return;
1072 }
1073
1074 /* reset timer that delays responses to clients while flooding is
1075 * not working */
1076 if (++iflods.open == 1)
1077 iflods_ok_timer = db_time.tv_sec + IFLODS_OK_SECS;
1078
1079 iflod_socks_connect(ifp);
1080 }
1081
1082
1083
1084 /* See if the new report is a duplicate of an old record in the database
1085 * db_sts.rcd.d points to the old record */
1086 static int /* -1=continue, 0=not dup, 1=dup */
1087 ck_dup_rcd(IFLOD_INFO *ifp,
1088 const DB_RCD *new, DCC_TGTS new_tgts_raw)
1089 {
1090 DCC_TGTS old_tgts;
1091 const DB_RCD_CK *new_ck, *old_ck;
1092 int new_num_cks, old_num_cks;
1093 int new_unique, old_unique;
1094
1095 /* ignore reports for deleted checksums
1096 * unless they are new reports or delete requests */
1097 old_tgts = DB_TGTS_RCD_RAW(db_sts.rcd.d.r);
1098 if (old_tgts == DCC_TGTS_DEL
1099 && new_tgts_raw != DCC_TGTS_DEL
1100 && !dcc_ts_newer_ts(&new->ts, &db_sts.rcd.d.r->ts)) {
1101 if (CK_FLOD_CNTERR(&ifp->ofp->lc.stale)
1102 && TMSG_FB2(ifp->ofp))
1103 flod_cnterr(&ifp->ofp->lc.stale,
1104 "ignore deleted %s after %s",
1105 rpt_id("report", new, ifp),
1106 rpt_id(0, db_sts.rcd.d.r, 0));
1107 return 1;
1108 }
1109
1110 /* not duplicate if the server-IDs or timestamps differ */
1111 if (DB_RCD_ID(new) != DB_RCD_ID(db_sts.rcd.d.r)
1112 || memcmp(&new->ts, &db_sts.rcd.d.r->ts, sizeof(new->ts)))
1113 return -1;
1114
1115 /* We know we have a duplicate
1116 * Stop looking if the old record has been deleted */
1117 if (old_tgts == 0)
1118 return 0;
1119
1120 /* look for the first real checksum in the new record */
1121 for (new_num_cks = DB_NUM_CKS(new), new_ck = new->cks;
1122 new_num_cks != 0;
1123 --new_num_cks, ++new_ck) {
1124 if (DB_CK_TYPE(new_ck) != DCC_CK_FLOD_PATH)
1125 break;
1126 }
1127
1128 /* do not even count duplicate server-ID declarations */
1129 if (DB_CK_TYPE(new_ck) == DCC_CK_SRVR_ID)
1130 return 1;
1131
1132 /* See if one record is a subset of the other */
1133 new_unique = 0;
1134 old_unique = 0;
1135 old_num_cks = DB_NUM_CKS(db_sts.rcd.d.r);
1136 old_ck = db_sts.rcd.d.r->cks;
1137 while (old_num_cks != 0 && new_num_cks != 0) {
1138 if (DB_CK_TYPE(old_ck) == DCC_CK_FLOD_PATH) {
1139 /* skip paths in the old record */
1140 ++old_ck;
1141 --old_num_cks;
1142 } else if (DB_CK_TYPE(old_ck) == DB_CK_TYPE(new_ck)) {
1143 /* skip identical checksums */
1144 ++old_ck;
1145 --old_num_cks;
1146 ++new_ck;
1147 --new_num_cks;
1148 } else if (DB_CK_TYPE(old_ck) < DB_CK_TYPE(new_ck)) {
1149 /* skip unique checksum in the old record,
1150 * using the ordering of checksums in records */
1151 ++old_unique;
1152 ++old_ck;
1153 --old_num_cks;
1154 } else {
1155 /* skip unique checksum in the new record */
1156 ++new_unique;
1157 ++new_ck;
1158 --new_num_cks;
1159 }
1160 }
1161
1162 /* forget the new record if it has nothing unique */
1163 if (new_unique+new_num_cks == 0) {
1164 if (CK_FLOD_CNTERR(&ifp->ofp->lc.dup)
1165 && TMSG_FB2(ifp->ofp))
1166 flod_cnterr(&ifp->ofp->lc.dup, "%sduplicate %s",
1167 old_unique+old_num_cks == 0
1168 ? "" : "subset ",
1169 rpt_id("report", new, ifp));
1170
1171 return 1;
1172 }
1173
1174 /* Keep both records if each has unique checksums
1175 * This inflates the count for common checksums, so hope it
1176 * is rare. */
1177 if (old_unique+old_num_cks != 0) {
1178 if (CK_FLOD_CNTERR(&ifp->ofp->lc.dup)
1179 && TMSG_FB2(ifp->ofp))
1180 flod_cnterr(&ifp->ofp->lc.dup, "partial duplicate %s",
1181 rpt_id("report", new, ifp));
1182
1183 return 0;
1184 }
1185
1186 /* Delete the original report if it has nothing unique
1187 * This results in doubling the contribution to the total for
1188 * each checksum from this report in our database until the
1189 * next time dbclean is run. At worst this could push a
1190 * DCC client over its bulk threshold */
1191 DB_TGTS_RCD_SET(db_sts.rcd.d.r, 0);
1192 SET_FLUSH_RCD_HDR(&db_sts.rcd, 1);
1193
1194 if (CK_FLOD_CNTERR(&ifp->ofp->lc.dup)
1195 && TMSG_FB2(ifp->ofp))
1196 flod_cnterr(&ifp->ofp->lc.dup, "superset duplicate %s",
1197 rpt_id("report", new, ifp));
1198 return 0;
1199 }
1200
1201
1202
1203 /* see if the new record is a duplicate of any existing records containing
1204 * the specified checksum
1205 * use db_sts.rcd for the initial record and the chain */
1206 static int /* -1=fail, 0=not dup, 1=duplicate */
1207 ck_dup_ck_chain(IFLOD_INFO *ifp, const DB_RCD *new, DCC_TGTS new_tgts_raw,
1208 DCC_CK_TYPES type, const DB_RCD_CK *found_ck)
1209 {
1210 DB_PTR next_rcd_pos;
1211 int cnt, i;
1212
1213 for (cnt = 0; ; ++cnt) {
1214 i = ck_dup_rcd(ifp, new, new_tgts_raw);
1215 if (i >= 0) {
1216 if (cnt >= 50 && (dccd_tracemask & DCC_TRACE_DB_BIT))
1217 dcc_trace_msg("long duplicate chain of %d"
1218 " from %s at %s",
1219 cnt, ifp->rem_hostname,
1220 rpt_id("report",new,ifp));
1221 return i;
1222 }
1223
1224 next_rcd_pos = DB_PTR_EX(found_ck->prev);
1225 if (next_rcd_pos == DB_PTR_NULL)
1226 return 0;
1227 if (next_rcd_pos >= db_sts.rcd.s.rptr) { /* prevent loops */
1228 db_error_msg(__LINE__,__FILE__,
1229 "bad %s link of "L_HPAT" at "L_HPAT,
1230 DB_TYPE2STR(type),
1231 db_sts.rcd.s.rptr, next_rcd_pos);
1232 return -1;
1233 }
1234
1235 found_ck = db_map_rcd_ck(dcc_emsg, &db_sts.rcd,
1236 next_rcd_pos, type);
1237 if (!found_ck) {
1238 iflod_close(ifp, 1, 1, 1, "%s", dcc_emsg);
1239 DB_ERROR_MSG(dcc_emsg);
1240 return -1;
1241 }
1242 }
1243 }
1244
1245
1246
1247 /* complain about a received flooded report,
1248 * and possibly close and so clear things */
1249 static u_char PATTRIB(6,7) /* 0=flood closed */
1250 iflod_rpt_complain(IFLOD_INFO *ifp,
1251 const DB_RCD *new, /* complain about this report */
1252 u_char serious, /* 0=send mere note, 1=send complaint */
1253 FLOD_LIMCNT *lc, /* limit complaints with this */
1254 const char *str, /* type of report */
1255 const char *pat,...) /* the complaint */
1256 {
1257 DCC_FLOD_RESP buf;
1258 const char *sc;
1259 va_list args;
1260 int i, len;
1261
1262 if (!lc && ifp->ofp)
1263 lc = &ifp->ofp->lc.iflod_bad;
1264 if (!lc) {
1265 sc = "";
1266 } else {
1267 i = ++lc->cur - (lc->lim + FLOD_LIM_COMPLAINTS);
1268 if (i > 0)
1269 return 1;
1270 sc = i < 0 ? "" : "; stop complaints";
1271 }
1272
1273 va_start(args, pat);
1274 len = vsnprintf(buf.note.str, sizeof(buf.note.str), pat, args);
1275 if (len >= ISZ(buf.note.str))
1276 len = sizeof(buf.note.str)-1;
1277 va_end(args);
1278
1279 if (serious) {
1280 dcc_error_msg("%s %s%s",
1281 buf.note.str, rpt_id(str, new, ifp), sc);
1282 db_ptr2flod_pos(buf.note.op, DCC_FLOD_POS_COMPLAINT);
1283 } else {
1284 TMSG3_FLOD2(ifp->ofp, "%s %s%s",
1285 buf.note.str, rpt_id(str, new, ifp), sc);
1286 db_ptr2flod_pos(buf.note.op, DCC_FLOD_POS_NOTE);
1287 }
1288
1289 len += snprintf(&buf.note.str[len], sizeof(buf.note.str)-len, " %s%s",
1290 rpt_id(str, new, 0), sc);
1291 if (len >= ISZ(buf.note.str))
1292 len = ISZ(buf.note.str)-1;
1293
1294 buf.note.len = len+1 + FLOD_NOTE_OVHD;
1295 return iflod_write(ifp, &buf, buf.note.len, buf.note.str, 0);
1296 }
1297
1298
1299
1300 static u_char
1301 parse_srvr_id(const DB_RCD_CK *ck, const IFLOD_INFO *ifp,
1302 const DB_RCD *new, DCC_SRVR_ID srvr_id)
1303 {
1304 DCC_SRVR_ID tgt_id, type_id;
1305 char buf1[24];
1306 OPT_FLAGS opt_flags;
1307 const OFLOD_INFO *ofp1;
1308 ID_TBL *tp;
1309
1310 /* notice server-ID type announcements */
1311 tgt_id = (ck->sum[1] << 8) + ck->sum[2];
1312 type_id = srvr_id;
1313 switch (type_id) {
1314 case DCC_ID_SRVR_REP_OK:
1315 type_id = DCC_ID_SRVR_SIMPLE;
1316 opt_flags = 0;
1317 break;
1318 case DCC_ID_SRVR_SIMPLE:
1319 opt_flags = FLOD_OPT_SIMPLE;
1320 break;
1321 case DCC_ID_SRVR_IGNORE:
1322 opt_flags = 0;
1323 break;
1324 case DCC_ID_SRVR_ROGUE:
1325 opt_flags = FLOD_OPT_ROGUE;
1326 break;
1327 default:
1328 return 0;
1329 }
1330 if (ck->sum[0] != DCC_CK_SRVR_ID) {
1331 return 0;
1332 }
1333
1334 tp = find_srvr_type(tgt_id);
1335 /* Restart flooding if the announced type of a peer changes. */
1336 for (ofp1 = oflods.infos; ofp1 <= LAST(oflods.infos); ++ofp1) {
1337 /* Wait a bit for more announcements before restarting
1338 * flooding. When we restart flooding, we will
1339 * check the database. */
1340 if (ofp1->rem_id == tgt_id) {
1341 if (opt_flags != (ofp1->o_opts.flags
1342 & (FLOD_OPT_ROGUE
1343 | FLOD_OPT_SIMPLE))) {
1344 if (TMSG_FB(ifp->ofp) || TMSG_FB(ofp1))
1345 dcc_trace_msg("server-ID %d for %s"
1346 " changed to \"%s\""
1347 " in %s",
1348 tgt_id,
1349 ofp1->rem_hostname,
1350 id2str(buf1, sizeof(buf1),
1351 type_id),
1352 rpt_id("report",new,ifp));
1353 if (flod_mtime > 1)
1354 flod_mtime = 1;
1355 }
1356 break;
1357 }
1358 }
1359
1360 /* accept changes to our records */
1361 tp->srvr_type = type_id;
1362
1363 return 1;
1364 }
1365
1366
1367
1368 /* consider an incoming flooded report */
1369 static int /* -1=failed, 0=not yet, else length */
1370 iflod_rpt(IFLOD_INFO *ifp, OFLOD_INFO *ofp,
1371 const DCC_FLOD_STREAM *stream, int max_len)
1372 {
1373 DB_PTR pos;
1374 DCC_TGTS new_tgts, found_tgts;
1375 DB_RCD new;
1376 DCC_SRVR_ID old_srvr, psrvr;
1377 const DCC_CK *ck_lim, *ck;
1378 const DB_RCD_CK *new_ck_lim, *srvr_id_ck;
1379 DB_RCD_CK *found_ck, *new_ck;
1380 DCC_CK_TYPES type, prev_type;
1381 DCC_FLOD_PATH_ID *new_path_id, *old_path_id;
1382 int num_path_blocks;
1383 char tgts_buf[DCC_XHDR_MAX_TGTS_LEN];
1384 int ok2;
1385 int rpt_len;
1386 u_char stale;
1387 ID_MAP_RESULT srvr_mapped;
1388 ID_TBL *tp;
1389 int i;
1390
1391 pos = flod_pos2db_ptr(stream->r.pos);
1392 if (pos < DCC_FLOD_POS_MIN) {
1393 iflod_close(ifp, 1, 1, 1,
1394 "bogus position "L_HPAT" in flooded report #%d",
1395 pos, ofp->cnts.total);
1396 return -1;
1397 }
1398
1399 /* wait for the header of the report */
1400 if (max_len < DCC_FLOD_RPT_LEN(0)) {
1401 return 0;
1402 }
1403
1404 if (stream->r.num_cks == 0 || stream->r.num_cks > DCC_QUERY_MAX) {
1405 iflod_close(ifp, 1, 1, 1,
1406 "impossible %d checksums in report #%d",
1407 stream->r.num_cks, ofp->cnts.total);
1408 return -1;
1409 }
1410 rpt_len = DCC_FLOD_RPT_LEN(stream->r.num_cks);
1411 if (rpt_len > max_len)
1412 return 0; /* wait for more */
1413
1414 if (db_failed_line)
1415 return rpt_len; /* can do nothing if database broken */
1416
1417 /* save the position to return to the sender */
1418 memcpy(ifp->pos, stream->r.pos, sizeof(ifp->pos));
1419
1420 new.ts = stream->r.ts;
1421 memcpy(&new.srvr_id_auth, stream->r.srvr_id_auth,
1422 sizeof(new.srvr_id_auth));
1423 old_srvr = ntohs(new.srvr_id_auth) & ~DCC_SRVR_ID_AUTH;
1424 new.srvr_id_auth = old_srvr;
1425 new.fgs_num_cks = 0;
1426
1427 memcpy(&new_tgts, stream->r.tgts, sizeof(new_tgts));
1428 new_tgts = ntohl(new_tgts);
1429 if (new_tgts == DCC_TGTS_DEL) {
1430 if (!(ofp->i_opts.flags & FLOD_OPT_DEL_OK)) {
1431 if (!iflod_rpt_complain(ifp, &new, 1,
1432 &ofp->lc.not_deleted,
1433 "delete request", "refuse"))
1434 return -1;
1435 return rpt_len;
1436 }
1437 } else if (new_tgts == 0
1438 || (new_tgts > DCC_TGTS_FLOD_RPT_MAX
1439 && new_tgts != DCC_TGTS_TOO_MANY)) {
1440 iflod_close(ifp, 1, 1, 1, "bogus target count %s in %s",
1441 dcc_tgts2str(tgts_buf, sizeof(tgts_buf),
1442 new_tgts, grey_on),
1443 rpt_id("report", &new, 0));
1444 return -1;
1445 } else if (ofp->i_opts.flags & FLOD_OPT_TRAPS) {
1446 /* comply if the source watches only spam traps */
1447 new_tgts = DCC_TGTS_TOO_MANY;
1448 }
1449
1450 /* notice reports from the distant future */
1451 if (dcc_ts_newer_ts(&new.ts, &future)) {
1452 if (!iflod_rpt_complain(ifp, &new, 1, &ofp->lc.stale,
1453 "report", "future"))
1454 return -1;
1455 return rpt_len;
1456 }
1457
1458 DB_TGTS_RCD_SET(&new, new_tgts);
1459 new.fgs_num_cks = 0;
1460 srvr_id_ck = 0;
1461 stale = 1;
1462 ck_lim = &stream->r.cks[stream->r.num_cks];
1463 new_ck = new.cks;
1464 num_path_blocks = 0;
1465
1466 tp = 0;
1467 srvr_mapped = id_map(old_srvr, &ofp->i_opts);
1468 switch (srvr_mapped) {
1469 case ID_MAP_NO:
1470 tp = find_srvr_type(old_srvr);
1471 break;
1472 case ID_MAP_REJ:
1473 if (!iflod_rpt_complain(ifp, &new, 0, 0,
1474 "rejected server-ID in", "refuse"))
1475 return -1;
1476 return rpt_len;
1477 case ID_MAP_SELF:
1478 new.srvr_id_auth = my_srvr_id;
1479 /* create path pointing to ourself if we translate the ID */
1480 memset(new_ck, 0, sizeof(*new_ck));
1481 new_ck->type_fgs = DCC_CK_FLOD_PATH;
1482 new_path_id = (DCC_FLOD_PATH_ID *)new_ck->sum;
1483 /* start the path with the ID of the previous hop because
1484 * we know it is defined */
1485 new_path_id->hi = ofp->rem_id>>8;
1486 new_path_id->lo = ofp->rem_id;
1487 new.fgs_num_cks = 1;
1488 ++new_ck;
1489 break;
1490 }
1491
1492 for (prev_type = DCC_CK_INVALID, ck = stream->r.cks;
1493 ck < ck_lim;
1494 prev_type = type, ++ck) {
1495 type = ck->type;
1496 if (!DCC_CK_OK_FLOD(grey_on, type)) {
1497 if (!iflod_rpt_complain(ifp, &new, 1, 0,
1498 "report",
1499 "unknown checksum type %s in",
1500 DB_TYPE2STR(type)))
1501 return -1;
1502 continue;
1503 }
1504 if (ck->len != sizeof(*ck)) {
1505 iflod_close(ifp, 1, 1, 1,
1506 "unknown checksum length %d in %s",
1507 ck->len, rpt_id("report", &new, 0));
1508 return -1;
1509 }
1510 if (type <= prev_type && prev_type != DCC_CK_FLOD_PATH) {
1511 if (!iflod_rpt_complain(ifp, &new, 1, 0,
1512 "report",
1513 "out of order %s checksum in",
1514 DB_TYPE2STR(type)))
1515 return -1;
1516 return rpt_len;
1517 }
1518
1519 new_ck->type_fgs = type;
1520 new_ck->prev = DB_PTR_CP(DB_PTR_NULL);
1521 memcpy(new_ck->sum, ck->sum, sizeof(new_ck->sum));
1522 if (type == DCC_CK_FLOD_PATH) {
1523 /* discard report if path is too long */
1524 if (++num_path_blocks > DCC_MAX_FLOD_PATH_CKSUMS) {
1525 TMSG2_FLOD(ofp, "%d path blocks in %s",
1526 num_path_blocks,
1527 rpt_id("report", &new, ifp));
1528 return rpt_len;
1529 }
1530 /* don't add this path if we translated the origin */
1531 if (srvr_mapped == ID_MAP_SELF)
1532 continue;
1533 old_path_id = (DCC_FLOD_PATH_ID *)ck->sum;
1534 new_path_id = old_path_id;
1535 for (i = 0; i < DCC_NUM_FLOD_PATH; ++i, ++old_path_id) {
1536 psrvr = (old_path_id->hi<<8) | old_path_id->lo;
1537 if (psrvr == DCC_ID_INVALID)
1538 break; /* end of path */
1539 switch (id_map(psrvr, &ofp->i_opts)) {
1540 case ID_MAP_NO:
1541 case ID_MAP_REJ:
1542 break;
1543 case ID_MAP_SELF:
1544 psrvr = my_srvr_id;
1545 break;
1546 }
1547 new_path_id->hi = psrvr>>8;
1548 new_path_id->lo = psrvr;
1549 ++new_path_id;
1550 }
1551
1552 } else {
1553 /* discard this checksum if we would not have kept
1554 * it if we had received the original report
1555 * and either its server-ID is translated
1556 * or it is not kept by default */
1557 if (DB_TEST_NOKEEP(db_parms.nokeep_cks, type)
1558 && (srvr_mapped == ID_MAP_SELF
1559 || DB_GLOBAL_NOKEEP(grey_on, type)))
1560 continue;
1561
1562 /* server-ID declarations are never stale */
1563 if (type == DCC_CK_SRVR_ID) {
1564 stale = 0;
1565 srvr_id_ck = new_ck;
1566 }
1567
1568 /* Notice if this checksum makes the report timely
1569 * We cannot detect duplicates of reports that
1570 * have expired, so consider stale anything older
1571 * than our expiration.
1572 * Ignore reports of checksums from crazy servers */
1573 if (stale
1574 && dcc_ts_newer_ts(&new.ts,
1575 new_tgts >= db_tholds[type]
1576 ? &db_parms.ex_spam[type]
1577 : &db_parms.ex_all[type])
1578 && (tp == 0
1579 || (tp->srvr_type != DCC_ID_SRVR_IGNORE
1580 && tp->srvr_type != DCC_ID_SRVR_ROGUE)))
1581 stale = 0;
1582 }
1583
1584 ++new_ck;
1585 ++new.fgs_num_cks;
1586 }
1587 if (stale) {
1588 if (CK_FLOD_CNTERR(&ofp->lc.stale)
1589 && TMSG_FB2(ofp))
1590 flod_cnterr(&ofp->lc.stale, "stale %s",
1591 rpt_id("report", &new, ifp));
1592 return rpt_len;
1593 }
1594
1595 if (!DB_NUM_CKS(&new)) {
1596 iflod_close(ifp, 1, 1, 1, "no known checksum types in %s",
1597 rpt_id("report", &new, 0));
1598 return -1;
1599 }
1600
1601 /* only now might we look at the database */
1602 if (db_lock() < 0) {
1603 iflod_close(ifp, 1, 1, 1, "iflod lock failure");
1604 return -1;
1605 }
1606
1607 /* See if the report is a duplicate.
1608 * Check all of the checksums to find one that is absent or
1609 * the one with the smallest total to minimize the number
1610 * of reports we must check to see if this is a duplicate */
1611 ok2 = 0;
1612 new_ck_lim = &new.cks[DB_NUM_CKS(&new)];
1613 for (new_ck = new.cks; new_ck < new_ck_lim; ++new_ck) {
1614 type = DB_CK_TYPE(new_ck);
1615 if (DB_TEST_NOKEEP(db_parms.nokeep_cks, type))
1616 continue;
1617
1618 switch (db_lookup(dcc_emsg, type, new_ck->sum,
1619 0, MAX_HASH_ENTRIES,
1620 &db_sts.hash, &db_sts.rcd, &found_ck)) {
1621 case DB_FOUND_LATER:
1622 case DB_FOUND_SYSERR:
1623 iflod_close(ifp, 1, 1, 1, "%s", dcc_emsg);
1624 DB_ERROR_MSG(dcc_emsg);
1625 return -1;
1626
1627 case DB_FOUND_IT:
1628 /* At least this checksum is already in the database */
1629 i = ck_dup_ck_chain(ifp, &new, new_tgts,
1630 type, found_ck);
1631 if (i < 0)
1632 return -1; /* broken database */
1633 if (i > 0)
1634 return rpt_len; /* duplicate */
1635
1636 /* Maybe not a duplicate.
1637 * Notice reports of checksums on the local server's
1638 * whitelist.
1639 * An ordinary checksum is whitelisted by DCC_TGTS_OK
1640 * or two reports with DCC_TGTS_OK2.
1641 * Greylisting uses DCC_TGTS_GREY_WHITE=DCC_TGTS_OK2
1642 * and so one report of DCC_TGTS_GREY_WHITE is enough */
1643 found_tgts = DB_TGTS_CK(found_ck);
1644 if (found_tgts == DCC_TGTS_OK
1645 || (found_tgts == DCC_TGTS_GREY_WHITE
1646 && (++ok2 >= 2 || grey_on))) {
1647 if (!iflod_rpt_complain(ifp, &new, 0,
1648 &ofp->lc.wlist,
1649 "report","whitelisted"))
1650 return -1;
1651 return rpt_len;
1652 }
1653 break;
1654
1655 case DB_FOUND_EMPTY:
1656 case DB_FOUND_CHAIN:
1657 case DB_FOUND_INTRUDER:
1658 /* We will fail to find this checksum in our database
1659 * if the new report is not a duplicate
1660 * or if it is a duplicate superset report */
1661 break;
1662 }
1663 }
1664
1665 /* If the new report is a delete request,
1666 * then we need to run dbclean to fix all of the
1667 * totals affected by the deleted reports. */
1668 if (new_tgts == DCC_TGTS_DEL) {
1669 if (!(ofp->i_opts.flags & FLOD_OPT_NO_LOG_DEL))
1670 dcc_trace_msg("accept %s",
1671 rpt_id("delete request", &new, ifp));
1672 if (!DCC_CK_IS_REP_OP(grey_on, type) && !grey_on)
1673 need_del_dbclean = "flood checksum deletion";
1674 }
1675
1676 if (srvr_id_ck) {
1677 /* discard translated server-ID declarations */
1678 if (srvr_mapped == ID_MAP_SELF) {
1679 TMSG2_FLOD(ofp, "translated server-ID from %d in %s",
1680 old_srvr, rpt_id("report", &new, ifp));
1681 return rpt_len;
1682 }
1683
1684 /* notice claims by other servers to our ID */
1685 if (old_srvr == my_srvr_id) {
1686 if (memcmp(host_id_sum, srvr_id_ck->sum,
1687 sizeof(host_id_sum)))
1688 dcc_error_msg("host %s used our server-ID"
1689 " %d at %s",
1690 dcc_ck2str_err(DCC_CK_SRVR_ID,
1691 srvr_id_ck->sum, 0),
1692 my_srvr_id,
1693 ts2str_err(&new.ts));
1694 return rpt_len;
1695 }
1696
1697 if (old_srvr < DCC_SRVR_ID_MIN
1698 && !parse_srvr_id(srvr_id_ck, ifp, &new, old_srvr))
1699 return rpt_len;
1700 }
1701
1702 /* the report is ok and not a duplicate, so add it to our database */
1703 if (!add_dly_rcd(&new, 1)) {
1704 iflod_close(ifp, 1, 1, 1, "%s", dcc_emsg);
1705 return -1;
1706 }
1707
1708 ++ofp->cnts.accepted;
1709 return rpt_len;
1710 }
1711
1712
1713
1714 static void
1715 bad_vers(IFLOD_INFO *ifp,
1716 u_char fail) /* 1=complain */
1717 {
1718 iflod_close(ifp, fail, fail, 1,
1719 DCC_FLOD_BAD_VER_MSG" need \""
1720 DCC_FLOD_VERSION_CUR_STR
1721 "\" not \"%.*s\"",
1722 LITZ(DCC_FLOD_VERSION_STR_BASE)+10,
1723 ifp->ibuf.s.v.body.str);
1724 }
1725
1726
1727
1728 /* authenticate and otherwise check a new incoming flood */
1729 static u_char /* 0=closed or switched to output */
1730 check_iflod_vers(IFLOD_INFO *ifp)
1731 {
1732 DCC_FNM_LNO_BUF fnm_buf;
1733 const DCC_FLOD_VERSION_HDR *vp;
1734 OFLOD_INFO *ofp;
1735 IFLOD_INFO *ifp1;
1736 const ID_TBL *tp;
1737 DCC_SRVR_ID rem_id;
1738 int iversion;
1739 int i;
1740
1741 vp = &ifp->ibuf.s.v;
1742 if (!strcmp(vp->body.str, DCC_FLOD_VERSION_CUR_STR)) {
1743 iversion = DCC_FLOD_VERSION_CUR;
1744 ifp->flags |= IFLOD_FG_VERS_CK;
1745
1746 #ifdef DCC_FLOD_VERSION7
1747 } else if (!strcmp(vp->body.str, DCC_FLOD_VERSION7_STR)) {
1748 iversion = DCC_FLOD_VERSION7;
1749 ifp->flags |= IFLOD_FG_VERS_CK;
1750
1751 #endif /* DCC_FLOD_VERSION7 */
1752
1753 } else if (!strncmp(vp->body.str, DCC_FLOD_VERSION_STR_BASE,
1754 LITZ(DCC_FLOD_VERSION_STR_BASE))) {
1755 /* it seems to be a DCC server,
1756 * so complain after identifying the peer */
1757 iversion = 1;
1758
1759 } else {
1760 /* junk, so complain and give up */
1761 bad_vers(ifp, 1);
1762 return 0;
1763 }
1764
1765 /* require a sane and familiar server-ID from the prospective peer */
1766 memcpy(&rem_id, vp->body.sender_srvr_id, sizeof(rem_id));
1767 rem_id = ntohs(rem_id);
1768 if (rem_id < DCC_SRVR_ID_MIN
1769 || rem_id > DCC_SRVR_ID_MAX) {
1770 iflod_close(ifp, 1, 1, 1, DCC_FLOD_BAD_ID_MSG" %d",
1771 rem_id);
1772 return 0;
1773 }
1774 for (ofp = oflods.infos; ; ++ofp) {
1775 if (ofp > LAST(oflods.infos)) {
1776 iflod_close(ifp, 1, 1, 1, DCC_FLOD_BAD_ID_MSG" %d",
1777 rem_id);
1778 return 0;
1779 }
1780 if (ofp->rem_id == rem_id) {
1781 ifp->ofp = ofp;
1782 STRLCPY(ifp->rem_hostname, ofp->rem_hostname,
1783 sizeof(ifp->rem_hostname));
1784 break;
1785 }
1786 }
1787
1788 /* ofp and ofp->mp are not null, because we now know which peer
1789 * it claims to be
1790 *
1791 * check that it knows the password */
1792 i = ck_sign(&tp, 0, ofp->in_passwd_id, vp, sizeof(*vp));
1793 if (!i) {
1794 if (!tp)
1795 iflod_close(ifp, 1, 1, 1, DCC_FLOD_PASSWD_ID_MSG" %d%s",
1796 ofp->in_passwd_id,
1797 fnm_lno(&fnm_buf, flod_path, ofp->lno));
1798 else
1799 iflod_close(ifp, 1, 1, 1, DCC_FLOD_BAD_AUTH_MSG" %d",
1800 ofp->in_passwd_id);
1801 return 0;
1802 }
1803 if (i == 1)
1804 ofp->mp->flags &= ~FLODMAP_FG_USE_2PASSWD;
1805 else
1806 ofp->mp->flags |= FLODMAP_FG_USE_2PASSWD;
1807
1808 /* no more assumed NAT games because it has contacted us */
1809 ofp->mp->flags &= ~FLODMAP_FG_NAT_AUTO;
1810
1811 /* Note the version of the protocol it is using so that we can use that
1812 * version when connecting to it. */
1813 ofp->mp->iversion = iversion;
1814 /* if we do not like its version, reject the connection and hope
1815 * that it will retry with a version we like */
1816 if (!(ifp->flags & IFLOD_FG_VERS_CK)) {
1817 bad_vers(ifp, iversion != 0);
1818 return 0;
1819 }
1820 if (iversion != DCC_FLOD_VERSION_CUR)
1821 TMSG2_FLOD(ofp, "version %d from %s",
1822 iversion, ifp_rem_str(ifp));
1823
1824 /* convert to a passive output flood as requested by the peer
1825 * This works even if the peer is configured to use SOCKS or NAT
1826 * but we are not using PASSIVE */
1827 if (vp->body.turn) {
1828 if (OFLOD_OPT_OFF_ROGUE(ofp)) {
1829 iflod_close(ifp, 1, 0, 1,
1830 "passive output flooding off from %s%s",
1831 ifp_rem_str(ifp),
1832 fnm_lno(&fnm_buf, flod_path, ofp->lno));
1833 return 0;
1834 }
1835
1836 /* We have a duplicate passive outgoing flood.
1837 * See whether the old stream has broken. */
1838 if (ofp->soc >= 0)
1839 oflod_read(ofp);
1840 /* If we still have a duplicate and we sent a shutdown request,
1841 * assume the response got lost */
1842 if (ofp->soc >= 0
1843 && (ofp->flags & OFLOD_FG_SHUTDOWN_REQ)) {
1844 rpt_err(ofp, 1, 0,
1845 " assume response to shutdown lost from %s",
1846 ofp_rem_str(ofp));
1847 oflod_close(ofp, 0);
1848 }
1849 if (ofp->soc >= 0) {
1850 /* We still have duplicates.
1851 * Reject the new one if the IP addresses differ */
1852 if (!DCC_SU_EQ(&ofp->rem_su, &ifp->rem_su)) {
1853 iflod_close(ifp, 1, 0, 1,
1854 "reject duplicate passive output"
1855 " flood from %s",
1856 ifp_rem_str(ifp));
1857 return 0;
1858 }
1859 rpt_err(ofp, 1, 0,
1860 "accept duplicate passive output flood from %s",
1861 ifp_rem_str(ifp));
1862 oflod_close(ofp, 0);
1863 }
1864
1865 ofp->soc = ifp->soc;
1866 ofp->rem_su = ifp->rem_su;
1867 ++oflods.open;
1868 TMSG1_FLOD(ofp,
1869 "convert incoming flood to passive outgoing to %s",
1870 ofp_rem_str(ofp));
1871 iflod_clear(ifp, 0);
1872
1873 ofp->mp->flags |= FLODMAP_FG_OUT_SRVR;
1874
1875 if (!oflod_connect_fin(ofp))
1876 oflod_close(ofp, 0);
1877 return 0;
1878 }
1879
1880 if (IFLOD_OPT_OFF_ROGUE(ofp)) {
1881 iflod_close(ifp, 1, 0, 1, "flood from %s turned off%s",
1882 ifp_rem_str(ifp),
1883 fnm_lno(&fnm_buf, flod_path, ofp->lno));
1884 return 0;
1885 }
1886
1887 /* detect duplicate incoming floods */
1888 for (ifp1 = iflods.infos; ifp1 <= LAST(iflods.infos); ++ifp1) {
1889 if (ifp1->ofp != ofp || ifp1 == ifp)
1890 continue;
1891
1892 /* We have a duplicate. Either two servers are using the
1893 * same server-ID or the peer has restarted flooding without
1894 * our seeing a clean shutdown.
1895 * If socket is in CLOSE_WAIT, then sending something will fail
1896 * immediately. If the peer was rebooted, then sending will
1897 * not fail for at least a round trip time and possibly longer
1898 * if the peer has moved.
1899 *
1900 * Before trying to send anything, check for a FIN waiting
1901 * on the other socket */
1902 for (i = 65536/FLOD_BUF_SIZE; i >= 0; --i) {
1903 if (iflod_read(ifp1))
1904 break;
1905 }
1906 /* forget it if reading closed the other stream */
1907 if (ifp1->ofp != ofp)
1908 break;
1909
1910 /* assume the it is ok if we have sent an end request */
1911 if (ifp1->flags & IFLOD_FG_END_REQ) {
1912 iflod_close(ifp1, 0, 0, 1,
1913 "missing end response;"
1914 " have replacement for flood from %s",
1915 ifp_rem_str(ifp1));
1916 break;
1917 }
1918
1919 /* assume we missed the shutdown
1920 * if the IP addresses are the same */
1921 if (DCC_SU_EQ(&ifp->rem_su, &ifp1->rem_su)) {
1922 iflod_close(ifp1, 0, 0, 1,
1923 "assumed dead link;"
1924 " have replacement for flood from %s",
1925 ifp_rem_str(ifp1));
1926 break;
1927 }
1928
1929 /* assume we do not have a duplicate server-ID and switch to
1930 * the new connection if sending a position or note
1931 * fails immediately, */
1932 if (0 >= iflod_send_pos(ifp1, 1)) {
1933 iflod_close(ifp1, 0, 0, 1,
1934 "have replacement for flood from %s",
1935 ifp_rem_str(ifp1));
1936 break;
1937 }
1938
1939 /* Otherwise, kill the new flood. If it was legitimate,
1940 * sending the note will eventually kill the old stream
1941 * and the peer will get through with it tries later */
1942 iflod_close(ifp, 1, 1, 1, "duplicate flood from %s",
1943 ifp_rem_str(ifp));
1944 return 0;
1945 }
1946
1947 ofp->ifp = ifp;
1948 if (ifp->flags & IFLOD_FG_CLIENT)
1949 ofp->mp->flags &= ~FLODMAP_FG_IN_SRVR;
1950 else
1951 ofp->mp->flags |= FLODMAP_FG_IN_SRVR;
1952 save_flod_cnts(ofp);
1953 ifp->iflod_alive = db_time.tv_sec;
1954
1955 /* Try to restart the corresponding output flood because a new
1956 * incoming flood might indicate that peer has awakened.
1957 * Kludge the backoff so that it does not increase. */
1958 if (ofp->soc < 0
1959 && !(ofp->o_opts.flags & FLOD_OPT_PASSIVE)) {
1960 ofp->mp->otimers.retry_secs /= 2;
1961 ofp->mp->otimers.retry = 0;
1962 oflod_open(ofp);
1963 }
1964
1965 /* Send a rewind or fast forward request immediately if needed.
1966 * If not, send a keepalive message so that peer knows we have
1967 * accepted the connection and it can stop worrying about an
1968 * immediate rejection. */
1969 if (0 > iflod_send_pos(ifp, 1))
1970 return 0;
1971
1972 return 1;
1973 }
1974
1975
1976
1977 /* A new SOCKS incoming stream that we originated has been closed by the
1978 * peer without authenticating itself. It could have responded to our
1979 * authentication with an error message. */
1980 static void
1981 parse_socks_error(IFLOD_INFO *ifp)
1982 {
1983 const DCC_FLOD_STREAM *stream;
1984 int i, msg_len;
1985 int fail;
1986
1987 stream = (DCC_FLOD_STREAM *)&ifp->ibuf.b[0];
1988 msg_len = ifp->ibuf_len - FLOD_END_OVHD;
1989
1990 /* it must look like an end request with an entirely ASCII message */
1991 if (flod_pos2db_ptr(stream->r.pos) != DCC_FLOD_POS_END
1992 || msg_len < 1 || msg_len > ISZ(stream->e.msg)) {
1993 iflod_close(ifp, 1, 1, 1, "SOCKS rejected with \"%.*s\"",
1994 msg_len, stream->e.msg);
1995 return;
1996 }
1997
1998 for (i = 0; i < msg_len; ++i) {
1999 if (stream->e.msg[i] < ' ' || stream->e.msg[i] > '~') {
2000 iflod_close(ifp, 1, 1, 1,
2001 "SOCKS rejected with \"%.*s\"",
2002 msg_len, stream->e.msg);
2003 return;
2004 }
2005 }
2006
2007 fail = oflod_parse_eof(ifp->ofp, 1, &stream->e, msg_len);
2008 if (fail <= 0) {
2009 iflod_socks_backoff(ifp->ofp);
2010 } else {
2011 /* try again immediately
2012 * with another protocol version or the 2nd password */
2013 ifp->ofp->mp->itimers.retry = 0;
2014 }
2015 iflod_close(ifp, fail<=0, fail<=0, 0,
2016 "SOCKS rejected by %s with \"%.*s\"",
2017 ifp_rem_str(ifp), msg_len, stream->e.msg);
2018 }
2019
2020
2021
2022 /* see what a distant flooder is telling us
2023 * can close the flood and so clear things */
2024 u_char /* 1=kernel buffers empty */
2025 iflod_read(IFLOD_INFO *ifp)
2026 {
2027 OFLOD_INFO *ofp;
2028 int off, req_len, recv_len;
2029 const DCC_FLOD_STREAM *stream;
2030 int len, i;
2031
2032 /* if this is an incoming SOCKS or NAT stream that we originated,
2033 * and if Rconnect() said "not yet" when we first tried to connect,
2034 * then we must be here because select() says it is time to
2035 * try Rconnect() again to finish the connection */
2036 if (!(ifp->flags & IFLOD_FG_CONNECTED)
2037 && iflod_socks_connect(ifp) <= 0)
2038 return 1;
2039
2040 /* read only once before returning
2041 * to ensure we pay attention to other work */
2042
2043 req_len = sizeof(ifp->ibuf) - ifp->ibuf_len;
2044 ofp = ifp->ofp;
2045 if (ofp && (ofp->o_opts.flags & FLOD_OPT_SOCKS))
2046 recv_len = Rrecv(ifp->soc, &ifp->ibuf.b[ifp->ibuf_len],
2047 req_len, 0);
2048 else
2049 recv_len = recv(ifp->soc, &ifp->ibuf.b[ifp->ibuf_len],
2050 req_len, 0);
2051 if (recv_len < 0) {
2052 /* If kernel ran out of data, stop for now.
2053 * Give up on an I/O error */
2054 if (!DCC_BLOCK_ERROR()) {
2055 iflod_close(ifp, 1, 0, 0, "incoming flood recv(%s): %s",
2056 ifp_rem_str(ifp), ERROR_STR());
2057 }
2058 return 1;
2059 }
2060 ifp->ibuf_len += recv_len;
2061
2062 off = 0;
2063
2064 /* deal with a new connection */
2065 if (!(ifp->flags & IFLOD_FG_VERS_CK)) {
2066 if (ifp->ibuf_len >= ISZ(DCC_FLOD_VERSION_HDR)) {
2067 if (!check_iflod_vers(ifp))
2068 return 1; /* stream closed or converted */
2069 ofp = ifp->ofp;
2070 off = ISZ(DCC_FLOD_VERSION_HDR);
2071
2072 } else if (recv_len != 0) {
2073 return 1; /* wait for rest of authentication */
2074
2075 } else if (ofp && ofp->mp
2076 && (ofp->mp->flags & FLODMAP_FG_ACT) != 0) {
2077 parse_socks_error(ifp);
2078 return 1;
2079
2080 } else {
2081 iflod_close(ifp, 1, 1, 0, "garbage connection from %s",
2082 ifp_rem_str(ifp));
2083 return 1;
2084 }
2085 }
2086 /* ofp != 0 because check_iflod_vers() has found the peer */
2087
2088 /* deal with the data */
2089 dcc_timeval2ts(&future, &db_time, MAX_FLOD_CLOCK_SKEW);
2090 while ((len = ifp->ibuf_len - off) > 0) {
2091 stream = (DCC_FLOD_STREAM *)&ifp->ibuf.b[off];
2092 if (len < ISZ(stream->r.pos))
2093 break; /* need at least the position */
2094 i = iflod_rpt(ifp, ofp, stream, len);
2095 if (i < 0)
2096 return 1; /* stream closed */
2097 if (i == 0)
2098 break; /* wait for rest of report */
2099 off += i;
2100 ++ofp->cnts.total;
2101 }
2102
2103 /* save unprocessed bytes for next time */
2104 if (off != 0) {
2105 ifp->ibuf_len -= off;
2106 if (ifp->ibuf_len < 0)
2107 dcc_logbad(EX_SOFTWARE, "ifp->ibuf_len=%d",
2108 ifp->ibuf_len);
2109 if (ifp->ibuf_len > 0)
2110 memmove(&ifp->ibuf.b[0], &ifp->ibuf.b[off],
2111 ifp->ibuf_len);
2112 }
2113
2114 if (recv_len == 0) {
2115 /* We are at EOF and have processed all input that we can. */
2116 if (ifp->ibuf_len != 0) {
2117 /* Something is wrong if any input remains, */
2118 iflod_close(ifp, 1, 0, 1, "report %d truncated",
2119 ofp ? ofp->cnts.total : 0);
2120 } else if (flods_st != FLODS_ST_ON
2121 || (ofp && IFLOD_OPT_OFF_ROGUE(ofp))) {
2122 iflod_close(ifp, 0, 0, 1, DCC_FLOD_OK_STR"%s off",
2123 our_hostname);
2124 } else {
2125 iflod_close(ifp, 0, 0, 1, DCC_FLOD_OK_STR"%s off",
2126 ifp_rem_str(ifp));
2127 }
2128 return 1;
2129 }
2130
2131 /* things are going ok, so reset the SOCKS restart backoff
2132 * and the no-connection complaint */
2133 ofp->mp->itimers.retry_secs = FLOD_SOCKS_SOCKS_IRETRY;
2134 ofp->mp->itimers.msg_secs = FLOD_IN_COMPLAIN1;
2135 ofp->mp->itimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN1;
2136
2137 return (req_len > recv_len);
2138 }
2139
2140
2141
2142 void
2143 iflods_listen(void)
2144 {
2145 SRVR_SOC *sp;
2146 DCC_SOCKU su;
2147 const DCC_SOCKU *sup = 0;
2148 int i, on;
2149
2150 for (sp = srvr_socs; sp; sp = sp->fwd) {
2151 if (sp->flags & SRVR_SOC_ADDR) {
2152 /* need to open a TCP listen socket for incoming floods
2153 * for each explicitly configured IP address */
2154 sup = &sp->su;
2155 } else if (sp->flags & SRVR_SOC_LISTEN) {
2156 /* need to open one TCP INADDR_ANY listen socket for
2157 * the first implicitly configured interface */
2158 sup = dcc_mk_su(&su, sp->su.sa.sa_family, 0,
2159 sp->su.ipv6.sin6_port);
2160 } else {
2161 /* otherwise close unneeded socket */
2162 iflod_listen_close(sp);
2163 continue;
2164 }
2165
2166 if (sp->listen >= 0)
2167 continue;
2168
2169 /* don't need to listen if there is no flooding */
2170 if (!oflods.total)
2171 continue;
2172
2173 TMSG1(FLOD, "start flood listening on %s",
2174 dcc_su2str_err(sup));
2175
2176 sp->listen = socket(sup->sa.sa_family, SOCK_STREAM, 0);
2177 if (sp->listen < 0) {
2178 dcc_error_msg("socket(flood listen %s): %s",
2179 dcc_su2str_err(sup), ERROR_STR());
2180 continue;
2181 }
2182
2183 if (-1 == fcntl(sp->listen, F_SETFL,
2184 fcntl(sp->listen, F_GETFL, 0) | O_NONBLOCK)) {
2185 dcc_error_msg("fcntl(flood listen %s, O_NONBLOCK): %s",
2186 dcc_su2str_err(sup), ERROR_STR());
2187 }
2188 on = 1;
2189 if (0 > setsockopt(sp->listen, SOL_SOCKET, SO_REUSEADDR,
2190 &on, sizeof(on)))
2191 dcc_error_msg("setsockopt(flood listen %s,"
2192 " SO_REUSADDR): %s",
2193 dcc_su2str_err(sup), ERROR_STR());
2194 if (0 > fcntl(sp->listen, F_SETFD, FD_CLOEXEC))
2195 dcc_error_msg("fcntl(flood listen %s FD_CLOEXEC): %s",
2196 dcc_su2str_err(sup), ERROR_STR());
2197
2198 i = bind(sp->listen, &sup->sa, DCC_SU_LEN(sup));
2199 if (0 > i) {
2200 dcc_error_msg("bind(flood listen %s): %s",
2201 dcc_su2str_err(sup), ERROR_STR());
2202 close(sp->listen);
2203 sp->listen = -1;
2204 continue;
2205 }
2206
2207 if (0 > listen(sp->listen, DCCD_MAX_FLOODS+1)) {
2208 dcc_error_msg("flood listen(%s): %s",
2209 dcc_su2str_err(sup), ERROR_STR());
2210 close(sp->listen);
2211 sp->listen = -1;
2212 }
2213 }
2214 }
2215
2216
2217
2218 static const char *
2219 oflod_state_str(char outstr[DCC_SU2STR_SIZE], const OFLOD_INFO *ofp,
2220 u_char anon)
2221 {
2222 if (ofp->soc >= 0) {
2223 if (ofp->flags & (OFLOD_FG_SHUTDOWN_REQ
2224 | OFLOD_FG_SHUTDOWN))
2225 return " (shutting)";
2226 if (!(ofp->flags & OFLOD_FG_CONNECTED))
2227 return " (connecting)";
2228 if (anon)
2229 return "";
2230 return dcc_su2str2(outstr, DCC_SU2STR_SIZE, &ofp->rem_su);
2231 }
2232
2233 if (OFLOD_OPT_OFF_ROGUE(ofp))
2234 return " (output off)";
2235 if (flods_st != FLODS_ST_ON)
2236 return " (flood off)";
2237 return " (no output)";
2238 }
2239
2240
2241
2242 static const char *
2243 iflod_state_str(char instr[DCC_SU2STR_SIZE],
2244 const OFLOD_INFO *ofp, const IFLOD_INFO *ifp,
2245 u_char anon, u_char have_in, u_char distinct_in)
2246 {
2247
2248 if (have_in) {
2249 if (!(ifp->flags & IFLOD_FG_VERS_CK))
2250 return " (connecting)";
2251 if (anon)
2252 return "";
2253 if (distinct_in)
2254 return dcc_su2str2(instr, DCC_SU2STR_SIZE, &ifp->rem_su);
2255 return "\t";
2256 }
2257 if (IFLOD_OPT_OFF_ROGUE(ofp))
2258 return " (input off)";
2259 if (flods_st != FLODS_ST_ON)
2260 return " (flood off)";
2261 return " (no input)";
2262 }
2263
2264
2265
2266 /* list the current flooders */
2267 int
2268 flods_list(char *buf, int buf_len, u_char anon)
2269 {
2270 #define FLODS_LIST_TOO_SHORT "buffer too short\n"
2271 #define FLODS_LIST_ALLOC(i) { \
2272 p += (i); \
2273 if ((buf_len -= (i)) <= 0) { \
2274 strcpy(p, FLODS_LIST_TOO_SHORT); \
2275 return (p-buf)+ISZ(FLODS_LIST_TOO_SHORT); \
2276 }}
2277 IFLOD_INFO *ifp;
2278 OFLOD_INFO *ofp;
2279 char instr[DCC_SU2STR_SIZE], outstr[DCC_SU2STR_SIZE];
2280 char hostname[60], fg_buf[60];
2281 DCC_SOCKU in, out;
2282 u_char have_in, distinct_in;
2283 int i;
2284 char *p;
2285
2286 if (buf_len < ISZ(FLODS_LIST_TOO_SHORT) +INET6_ADDRSTRLEN+1)
2287 return 0;
2288
2289 buf_len -= ISZ(FLODS_LIST_TOO_SHORT);
2290 p = buf;
2291 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) {
2292 if (ofp->rem_hostname[0] == '\0')
2293 break;
2294 have_in = 0;
2295 distinct_in = 0;
2296 for (ifp = iflods.infos; ifp <= LAST(iflods.infos); ++ifp) {
2297 if (ifp->ofp == ofp) {
2298 if (ifp->soc >= 0) {
2299 have_in = 1;
2300 dcc_ipv6sutoipv4(&in, &ifp->rem_su);
2301 dcc_ipv6sutoipv4(&out, &ofp->rem_su);
2302 if (ofp->soc < 0
2303 || !DCC_SU_EQ(&in, &out))
2304 distinct_in = 1;
2305 }
2306 break;
2307 }
2308 }
2309 if (anon) {
2310 i = snprintf(p, buf_len, "%5d %15s\t%s\n",
2311 ofp->rem_id,
2312 oflod_state_str(outstr, ofp, 1),
2313 iflod_state_str(instr, ofp, ifp,
2314 1, have_in, 0));
2315 } else {
2316 dcc_host_portname(hostname, sizeof(hostname),
2317 ofp->rem_hostname,
2318 ofp->rem_port == def_port
2319 ? 0 : ofp->rem_portname),
2320 i = strlen(hostname);
2321 flodmap_fg(fg_buf, sizeof(fg_buf),
2322 i < 16 ? "\t\t" : i > 24 ? " " : "\t",
2323 ofp->mp);
2324 i = snprintf(p, buf_len, "%5d %15s\t%s\t%s%s\n",
2325 ofp->rem_id,
2326 oflod_state_str(outstr, ofp, 0),
2327 iflod_state_str(instr, ofp, ifp,
2328 0, have_in, distinct_in),
2329 hostname,
2330 fg_buf);
2331 }
2332 FLODS_LIST_ALLOC(i);
2333 }
2334
2335 for (ifp = iflods.infos; ifp <= LAST(iflods.infos); ++ifp) {
2336 if (ifp->soc < 0 || ifp->ofp != 0)
2337 continue; /* already handled this one */
2338
2339 /* say something about an incomplete connection */
2340 i = snprintf(p, buf_len, " ? %s\n", ifp->rem_hostname);
2341 FLODS_LIST_ALLOC(i);
2342 }
2343 if (p > buf)
2344 --p; /* trim trailing '\n' */
2345 return p-buf;
2346 #undef FLODS_LIST_TOO_SHORT
2347 #undef FLODS_LIST_ALLOC
2348 }
2349
2350
2351
2352 static PATTRIB(3,4) u_char /* 0=no room */
2353 flod_stats_str(char **buf, int *buf_len,
2354 const char *pat, ...)
2355 {
2356 int i;
2357 va_list args;
2358
2359 if (*buf_len <= 0)
2360 return 0;
2361
2362 va_start(args, pat);
2363 i = vsnprintf(*buf, *buf_len, pat, args);
2364 va_end(args);
2365
2366 if ((*buf_len -= i) <= 0) {
2367 *buf_len = 0;
2368 return 0;
2369 }
2370 *buf += i;
2371 return 1;
2372 }
2373
2374
2375
2376
2377 static u_char /* 0=no room */
2378 flod_stats_time(char **buf, int *buf_len,
2379 const char *str, const char *timepat, time_t when)
2380 {
2381 char timebuf[40];
2382
2383 return flod_stats_str(buf, buf_len, "%s %s", str,
2384 dcc_time2str(timebuf, sizeof(timebuf), timepat,
2385 when));
2386 }
2387
2388
2389
2390 static void
2391 flod_stats_conn_total(char **buf, int *buf_len,
2392 const char *label, int connected)
2393 {
2394 int i;
2395
2396 if (*buf_len <= 0)
2397 return;
2398
2399 i = snprintf(*buf, *buf_len,
2400 "\n %s connected a total of %d days %d:%02d:%02d\n",
2401 label,
2402 connected/(24*60*60),
2403 (connected/(60*60)) % 24,
2404 (connected/60) % 60,
2405 connected % 60);
2406 *buf += i;
2407 *buf_len -= i;
2408 }
2409
2410
2411
2412 static void
2413 flod_stats_conn_cur(char **buf, int *buf_len, const OFLOD_INFO *ofp, u_char in)
2414 {
2415 u_char connected;
2416 time_t conn_changed;
2417 time_t flod_alive;
2418 const FLOD_MMAP *mp;
2419 const LAST_ERROR *ep;
2420 DCC_FNM_LNO_BUF fnm_buf;
2421 time_t deadline;
2422 u_char passive;
2423 const char *msg;
2424
2425 if (*buf_len <= 0)
2426 return;
2427
2428 mp = ofp->mp;
2429
2430 if (in) {
2431 connected = ofp->ifp != 0;
2432 conn_changed = ofp->mp->cnts.in_conn_changed;
2433 flod_alive = ofp->ifp ? ofp->ifp->iflod_alive : 0;
2434 } else {
2435 connected = (ofp->flags & OFLOD_FG_CONNECTED) != 0;
2436 conn_changed = ofp->mp->cnts.out_conn_changed;
2437 flod_alive = ofp->oflod_alive;
2438 }
2439
2440 if (connected) {
2441 if (conn_changed >= mp->cnts.cnts_cleared
2442 && !flod_stats_time(buf, buf_len, " connected since",
2443 "%b %d %X", conn_changed))
2444 return;
2445 flod_stats_time(buf, buf_len, " last active", "%X",
2446 flod_alive);
2447 return;
2448 }
2449
2450 if ((in && (mp->flags & FLODMAP_FG_IN_OFF))
2451 || (!in && (mp->flags & FLODMAP_FG_OUT_OFF))) {
2452 flod_stats_str(buf, buf_len, " off%s",
2453 fnm_lno(&fnm_buf, flod_path, ofp->lno));
2454 return;
2455 }
2456
2457 if (!flod_stats_str(buf, buf_len, " not connected"))
2458 return;
2459 if (conn_changed >= mp->cnts.cnts_cleared) {
2460 if (!flod_stats_time(buf, buf_len, " since",
2461 "%b %d %X", conn_changed))
2462 return;
2463 }
2464 ep = in ? &mp->iflod_err : &mp->oflod_err;
2465 msg = ep->msg[0] != '\0' ? ep->msg : ep->trace_msg;
2466 if (msg[0] != '\0') {
2467 if (!flod_stats_str(buf, buf_len, "\n\t%s", msg))
2468 return;
2469 }
2470
2471 if (!FLODS_OK_ON()) {
2472 flod_stats_str(buf, buf_len, "\n flooding off");
2473 return;
2474 }
2475
2476 if (in) {
2477 if ((ofp->mp->flags & FLODMAP_FG_ACT) != 0) {
2478 passive = 0;
2479 deadline = ofp->mp->itimers.retry;
2480 if (DB_IS_TIME(deadline, ofp->mp->itimers.retry_secs))
2481 deadline = 0;
2482
2483 } else {
2484 passive = 1;
2485 deadline = ofp->mp->itimers.msg;
2486 if (DB_IS_TIME(deadline, ofp->mp->itimers.msg_secs))
2487 deadline = 0;
2488 }
2489 } else {
2490 if (ofp->mp->flags & FLODMAP_FG_PASSIVE) {
2491 passive = 1;
2492 deadline = ofp->mp->otimers.msg;
2493 if (DB_IS_TIME(deadline, ofp->mp->otimers.msg_secs))
2494 deadline = 0;
2495 } else {
2496 passive = 0;
2497 deadline = ofp->mp->otimers.retry;
2498 if (DB_IS_TIME(deadline, ofp->mp->otimers.retry_secs))
2499 deadline = 0;
2500 }
2501 }
2502 if (deadline == 0) {
2503 flod_stats_str(buf, buf_len,
2504 passive
2505 ? "\n complain soon"
2506 : "\n try again soon");
2507 } else {
2508 flod_stats_time(buf, buf_len,
2509 passive
2510 ? "\n complain after"
2511 : "\n try again after",
2512 "%b %d %X", deadline);
2513 }
2514 }
2515
2516
2517
2518 /* list the counts for a flood */
2519 int /* -1 or buffer length */
2520 flod_stats(char *buf, int buf_len, u_int32_t tgt, u_char clear)
2521 {
2522 #define FLOD_STATS_TOO_SHORT "buffer too short\n"
2523 #define FLOD_STATS_ALLOC(i) (p += (i), len -= (i))
2524 OFLOD_INFO *ofp, *ofp1;
2525 FLOD_MMAP *mp;
2526 char now_buf[26], time_buf[26], fg_buf[60];
2527 DCC_SRVR_ID min_srvr, max_srvr;
2528 u_char loaded;
2529 int len, i;
2530 char *p;
2531
2532 if (buf_len < ISZ(FLOD_STATS_TOO_SHORT))
2533 return 0;
2534 len = buf_len - ISZ(FLOD_STATS_TOO_SHORT);
2535 p = buf;
2536
2537 if (flod_mmaps) {
2538 loaded = 0;
2539 } else if (!load_flod(0)) {
2540 return -1;
2541 } else {
2542 loaded = 1;
2543 }
2544
2545 if (tgt <= DCC_SRVR_ID_MAX) {
2546 /* an explicit target server-ID was specified */
2547 min_srvr = max_srvr = tgt;
2548 } else {
2549 /* look for next server-ID after the target value */
2550 min_srvr = tgt - DCC_SRVR_ID_MAX;
2551 max_srvr = DCC_SRVR_ID_MAX;
2552 }
2553 ofp = 0;
2554 for (ofp1 = oflods.infos; ofp1 <= LAST(oflods.infos); ++ofp1) {
2555 if (ofp1->rem_hostname[0] != '\0'
2556 && ofp1->rem_id >= min_srvr
2557 && ofp1->rem_id <= max_srvr) {
2558 /* This peer fits and is the best so far. */
2559 ofp = ofp1;
2560 max_srvr = ofp->rem_id-1;
2561 }
2562 }
2563 if (!ofp) {
2564 i = snprintf(p, len,
2565 DCC_AOP_FLOD_STATS_ID"unknown remote server-ID",
2566 tgt);
2567 FLOD_STATS_ALLOC(i);
2568 if (loaded)
2569 oflods_clear();
2570 return p-buf;
2571 }
2572 mp = ofp->mp;
2573
2574 save_flod_cnts(ofp);
2575 i = snprintf(p, len,
2576 DCC_AOP_FLOD_STATS_ID" %s%s %s\n status start %s",
2577 ofp->rem_id, mp->rem_hostname,
2578 flodmap_fg(fg_buf, sizeof(fg_buf), " ", mp),
2579 dcc_time2str(now_buf, sizeof(now_buf), "%b %d %X %Z",
2580 db_time.tv_sec),
2581 dcc_time2str(time_buf, sizeof(time_buf), "%b %d %X %Z",
2582 mp->cnts.cnts_cleared));
2583 FLOD_STATS_ALLOC(i);
2584
2585 flod_stats_conn_total(&p, &len, "output", mp->cnts.out_total_conn);
2586 i = snprintf(p, len, " "L_DPAT" reports sent\n",
2587 mp->cnts.out_reports+ofp->cnts.out_reports);
2588 FLOD_STATS_ALLOC(i);
2589 flod_stats_conn_cur(&p, &len, ofp, 0);
2590 i = snprintf(p, len, "\n position "L_HPAT, mp->confirm_pos);
2591 FLOD_STATS_ALLOC(i);
2592
2593 flod_stats_conn_total(&p, &len, "input", mp->cnts.in_total_conn);
2594 i = snprintf(p, len,
2595 " "L_DPAT" reports received "L_DPAT" accepted"
2596 " "L_DPAT" duplicate "L_DPAT" stale\n"
2597 " "L_DPAT" bad whitelist "L_DPAT" not deleted\n",
2598 mp->cnts.total+ofp->cnts.total,
2599 mp->cnts.accepted+ofp->cnts.accepted,
2600 mp->cnts.dup+ofp->lc.dup.cur,
2601 mp->cnts.stale+ofp->lc.stale.cur,
2602 mp->cnts.wlist+ofp->lc.wlist.cur,
2603 mp->cnts.not_deleted+ofp->lc.not_deleted.cur);
2604 FLOD_STATS_ALLOC(i);
2605 flod_stats_conn_cur(&p, &len, ofp, 1);
2606
2607 if (len <= 0) {
2608 strcpy(buf, FLOD_STATS_TOO_SHORT);
2609 if (loaded)
2610 oflods_clear();
2611 return ISZ(FLOD_STATS_TOO_SHORT);
2612 }
2613
2614 if (clear) {
2615 flod_try_again(ofp);
2616 save_flod_cnts(ofp);
2617 ofp->limit_reset = 0;
2618 memset(&mp->cnts, 0, sizeof(mp->cnts));
2619 mp->cnts.cnts_cleared = db_time.tv_sec;
2620 }
2621
2622 if (loaded)
2623 oflods_clear();
2624 return p-buf;
2625 #undef FLOD_STATS_TOO_SHORT
2626 #undef FLOD_STATS_ALLOC
2627 }