Mercurial > notdcc
comparison dccd/oflod.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 outgoing 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.151 $Revision$ | |
40 */ | |
41 | |
42 #include "dccd_defs.h" | |
43 #include "dcc_ck.h" | |
44 | |
45 | |
46 int flods_off; /* # of reasons flooding is off */ | |
47 | |
48 time_t next_flods_ck; | |
49 time_t flod_mtime = 1; | |
50 enum FLODS_ST flods_st = FLODS_ST_OFF; | |
51 OFLODS oflods; | |
52 | |
53 /* records after this have not been flooded | |
54 * 0 if invalid */ | |
55 DB_PTR oflods_max_cur_pos; | |
56 | |
57 int summarize_delay_secs; /* delay summaries by this */ | |
58 | |
59 | |
60 static void oflod_fill(OFLOD_INFO *); | |
61 | |
62 | |
63 /* the socket must already be closed */ | |
64 static void | |
65 oflod_clear(OFLOD_INFO *ofp) | |
66 { | |
67 memset(ofp, 0, sizeof(*ofp)); | |
68 ofp->soc = -1; | |
69 } | |
70 | |
71 | |
72 | |
73 void | |
74 oflods_clear(void) | |
75 { | |
76 OFLOD_INFO *ofp; | |
77 | |
78 iflods_stop("", 1); /* paranoia */ | |
79 | |
80 flod_unmap(0, &dccd_stats); | |
81 | |
82 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) | |
83 oflod_clear(ofp); | |
84 oflods.total = 0; | |
85 complained_many_iflods = 0; | |
86 oflods_max_cur_pos = 0; | |
87 } | |
88 | |
89 | |
90 | |
91 /* parse ID1->tgt in a flood file entry */ | |
92 static char | |
93 oflod_parse_map(OFLOD_OPTS *opts, const char *str0, int lno) | |
94 { | |
95 DCC_FNM_LNO_BUF fnm_buf; | |
96 const char *str; | |
97 OFLOD_SRVR_ID_MAP *imp; | |
98 | |
99 if (opts->num_maps >= DIM(opts->srvr_map)) { | |
100 dcc_error_msg("too many ID mappings with\"%s\"%s", | |
101 str0, fnm_lno(&fnm_buf, flod_path, lno)); | |
102 return 0; | |
103 } | |
104 imp = &opts->srvr_map[opts->num_maps]; | |
105 | |
106 if (!CLITCMP(str0, "self->")) { | |
107 str = str0+LITZ("self->"); | |
108 imp->from_lo = imp->from_hi = my_srvr_id; | |
109 } else if (!CLITCMP(str0, "all->")) { | |
110 str = str0+LITZ("all->"); | |
111 imp->from_lo = DCC_SRVR_ID_MIN; | |
112 imp->from_hi = DCC_SRVR_ID_MAX; | |
113 } else { | |
114 /* get ID1 */ | |
115 str = dcc_get_srvr_id(0, &imp->from_lo, str0, "-", | |
116 flod_path, lno); | |
117 if (!str) | |
118 return 0; | |
119 if (str[0] == '-' && str[1] == '>') { | |
120 /* ID1 is not a range */ | |
121 imp->from_hi = imp->from_lo; | |
122 } else { | |
123 /* ID1 is a range of IDs */ | |
124 str = dcc_get_srvr_id(0, &imp->from_hi, | |
125 str+1, "-", flod_path, lno); | |
126 if (!str) | |
127 return 0; | |
128 if (imp->from_hi < imp->from_lo) { | |
129 dcc_error_msg("invalid ID mapping range " | |
130 "\"%d-%d\"%s", | |
131 imp->from_lo, imp->from_hi, | |
132 fnm_lno(&fnm_buf, | |
133 flod_path, lno)); | |
134 return 0; | |
135 } | |
136 } | |
137 if (*str++ != '-' || *str++ != '>') { | |
138 dcc_error_msg("invalid server-ID mapping \"%s\"%s", | |
139 str0, fnm_lno(&fnm_buf, flod_path, lno)); | |
140 return 0; | |
141 } | |
142 } | |
143 if (!strcasecmp(str, "self")) { | |
144 imp->result = ID_MAP_SELF; | |
145 } else if (!strcasecmp(str, "reject")) { | |
146 imp->result = ID_MAP_REJ; | |
147 } else if (!strcasecmp(str, "ok")) { | |
148 imp->result = ID_MAP_NO; | |
149 } else { | |
150 dcc_error_msg("invalid ID mapping result \"%s\"%s", | |
151 str, fnm_lno(&fnm_buf, flod_path, lno)); | |
152 return 0; | |
153 } | |
154 | |
155 ++opts->num_maps; | |
156 return 1; | |
157 } | |
158 | |
159 | |
160 | |
161 static u_char | |
162 ck_socks_flags(OFLOD_INFO *ofp, OPT_FLAGS new, | |
163 DCC_FNM_LNO_BUF fnm_buf, int lno) | |
164 { | |
165 if (0 != (ofp->o_opts.flags & (FLOD_OPT_PASSIVE | FLOD_OPT_SOCKS | |
166 | FLOD_OPT_NAT) | |
167 & ~new)) { | |
168 dcc_error_msg("only one of \"passive\", \"SOCKS\", or \"NAT\"" | |
169 " allowed%s", | |
170 fnm_lno(&fnm_buf, flod_path, lno)); | |
171 return 0; | |
172 } | |
173 | |
174 if ((new & (FLOD_OPT_SOCKS | FLOD_OPT_NAT)) != 0 | |
175 && (ofp->loc_hostname[0] != '\0' || ofp->loc_port != 0)) { | |
176 dcc_error_msg("source host name or port number" | |
177 " and \"SOCKS\" or \"NAT\"" | |
178 " cannot both be set%s", | |
179 fnm_lno(&fnm_buf, flod_path, lno)); | |
180 ofp->loc_hostname[0] = '\0'; | |
181 ofp->loc_port = 0; | |
182 } | |
183 | |
184 ofp->o_opts.flags |= new; | |
185 return 1; | |
186 } | |
187 | |
188 | |
189 | |
190 /* parse remote or local options that can be any of | |
191 * a "off", "del", "no-del", "log-del", "passive", ID->map, etc. */ | |
192 static const char * /* rest of the line */ | |
193 parse_flod_opts(OFLOD_INFO *ofp, | |
194 OFLOD_OPTS *opts, | |
195 const char *buf, int lno) | |
196 { | |
197 DCC_FNM_LNO_BUF fnm_buf; | |
198 char opts_buf[200]; | |
199 char opt[20]; | |
200 const char *buf_ptr, *p; | |
201 char *end; | |
202 unsigned long l; | |
203 u_int olen; | |
204 | |
205 /* pick out the blank delimited string of options */ | |
206 buf = dcc_parse_word(0, opts_buf, sizeof(opts_buf), | |
207 buf, "flood options", flod_path, lno); | |
208 if (!buf) | |
209 return 0; | |
210 | |
211 opts->path_len = DCC_MAX_FLOD_PATH; | |
212 if (grey_on) | |
213 opts->flags |= (FLOD_OPT_DEL_OK | |
214 | FLOD_OPT_NO_LOG_DEL | |
215 | FLOD_OPT_DEL_SET); | |
216 | |
217 /* parse the options */ | |
218 buf_ptr = opts_buf; | |
219 while (*buf_ptr != '\0') { | |
220 if (*buf_ptr == ',') { | |
221 ++buf_ptr; | |
222 continue; | |
223 } | |
224 olen = strcspn(buf_ptr, ","); | |
225 if (olen >= sizeof(opt)) | |
226 olen = sizeof(opt)-1; | |
227 strncpy(opt, buf_ptr, olen); | |
228 opt[olen] = '\0'; | |
229 buf_ptr += olen; | |
230 | |
231 /* ignore "-" */ | |
232 if (!strcmp(opt, "-")) | |
233 continue; | |
234 | |
235 if (!strcasecmp(opt, "off")) { | |
236 opts->flags |= FLOD_OPT_OFF; | |
237 continue; | |
238 } | |
239 | |
240 if (!grey_on) { | |
241 if (!strcasecmp(opt, "traps")) { | |
242 opts->flags |= FLOD_OPT_TRAPS; | |
243 continue; | |
244 } | |
245 if (!strcasecmp(opt, "no-del")) { | |
246 opts->flags &= ~FLOD_OPT_DEL_OK; | |
247 opts->flags |= FLOD_OPT_DEL_SET; | |
248 continue; | |
249 } | |
250 if (!strcasecmp(opt, "del")) { | |
251 opts->flags |= FLOD_OPT_DEL_OK; | |
252 opts->flags |= FLOD_OPT_DEL_SET; | |
253 continue; | |
254 } | |
255 } | |
256 | |
257 /* put some options in one or the other flag word no matter | |
258 * for which they are specified */ | |
259 if (!strcasecmp(opt, "trace")) { | |
260 ofp->o_opts.flags |= FLOD_OPT_TRACE; | |
261 continue; | |
262 } | |
263 if (!strcasecmp(opt, "trace2")) { | |
264 ofp->o_opts.flags |= FLOD_OPT_TRACE2; | |
265 continue; | |
266 } | |
267 | |
268 if (!strcasecmp(opt, "no-log-del")) { | |
269 ofp->i_opts.flags |= FLOD_OPT_NO_LOG_DEL; | |
270 continue; | |
271 } | |
272 if (!strcasecmp(opt, "log-del")) { | |
273 ofp->i_opts.flags &= ~FLOD_OPT_NO_LOG_DEL; | |
274 continue; | |
275 } | |
276 if (!strcasecmp(opt, "passive")) { | |
277 if (!ck_socks_flags(ofp, FLOD_OPT_PASSIVE, | |
278 fnm_buf, lno)) | |
279 return 0; | |
280 continue; | |
281 } | |
282 if (!strcasecmp(opt, "socks")) { | |
283 if (!ck_socks_flags(ofp, FLOD_OPT_SOCKS, | |
284 fnm_buf, lno)) | |
285 return 0; | |
286 continue; | |
287 } | |
288 if (!strcasecmp(opt, "nat")) { | |
289 if (!ck_socks_flags(ofp, FLOD_OPT_NAT, | |
290 fnm_buf, lno)) | |
291 return 0; | |
292 continue; | |
293 } | |
294 if (!strcasecmp(opt, "IPv4")) { | |
295 if (ofp->o_opts.flags & FLOD_OPT_IPv6) { | |
296 dcc_error_msg("\"IPv4\" and \"IPv6\";" | |
297 " cannot both be%s", | |
298 fnm_lno(&fnm_buf, | |
299 flod_path, lno)); | |
300 return 0; | |
301 } | |
302 ofp->o_opts.flags |= FLOD_OPT_IPv4; | |
303 continue; | |
304 } | |
305 if (!strcasecmp(opt, "IPv6")) { | |
306 if (ofp->o_opts.flags & FLOD_OPT_IPv4) { | |
307 dcc_error_msg("\"IPv4\" and \"IPv6\";" | |
308 " cannot both be%s", | |
309 fnm_lno(&fnm_buf, | |
310 flod_path, lno)); | |
311 return 0; | |
312 } | |
313 ofp->o_opts.flags |= FLOD_OPT_IPv6; | |
314 continue; | |
315 } | |
316 if (!CLITCMP(opt, "leaf=") | |
317 && (l = strtoul(opt+LITZ("leaf="), &end, 10), | |
318 *end == '\0')) { | |
319 if (l > DCC_MAX_FLOD_PATH) | |
320 l = DCC_MAX_FLOD_PATH; | |
321 ofp->o_opts.path_len = l; | |
322 continue; | |
323 } | |
324 | |
325 #ifdef DCC_FLOD_VERSION7 | |
326 if (!strcasecmp(opt, "version7")) { | |
327 ofp->oversion = DCC_FLOD_VERSION7; | |
328 continue; | |
329 } | |
330 | |
331 #endif | |
332 /* parse an ID->map */ | |
333 p = strchr(opt, '>'); | |
334 if (p && p > opt && *(p-1) == '-') { | |
335 if (!oflod_parse_map(opts, opt, lno)) | |
336 return 0; | |
337 continue; | |
338 } | |
339 | |
340 dcc_error_msg("unknown option \"%s\"%s", | |
341 opt, fnm_lno(&fnm_buf, flod_path, lno)); | |
342 return 0; | |
343 } | |
344 | |
345 return buf; | |
346 } | |
347 | |
348 | |
349 | |
350 static const char * /* rest of a flod file line */ | |
351 oflod_parse_id(DCC_SRVR_ID *id, | |
352 const char *buf, const char *type, int lno) | |
353 { | |
354 char id_buf[20]; | |
355 | |
356 buf = dcc_parse_word(0, id_buf, sizeof(id_buf), | |
357 buf, type, flod_path, lno); | |
358 if (!buf) | |
359 return 0; | |
360 | |
361 if (!strcmp(id_buf, "-") | |
362 || id_buf[0] == '\0') { | |
363 *id = DCC_ID_INVALID; | |
364 return buf; | |
365 } | |
366 | |
367 if (!dcc_get_srvr_id(0, id, id_buf, 0, flod_path, lno)) | |
368 return 0; | |
369 | |
370 /* do not check whether we know the local ID here, because | |
371 * changes in the ids file can make that check moot */ | |
372 | |
373 return buf; | |
374 } | |
375 | |
376 | |
377 | |
378 /* compute the maximum position among all floods */ | |
379 static void | |
380 get_oflods_max_cur_pos(void) | |
381 { | |
382 OFLOD_INFO *ofp; | |
383 | |
384 oflods_max_cur_pos = DB_PTR_BASE; | |
385 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) { | |
386 if (ofp->rem_hostname[0] != '\0' | |
387 && oflods_max_cur_pos < ofp->cur_pos) | |
388 oflods_max_cur_pos = ofp->cur_pos; | |
389 } | |
390 } | |
391 | |
392 | |
393 | |
394 static void | |
395 copy_opts2mp(OFLOD_INFO *ofp) | |
396 { | |
397 FLOD_MMAP *mp; | |
398 FLOD_MMAP_FLAGS new_flags; | |
399 u_char changed; | |
400 | |
401 mp = ofp->mp; | |
402 changed = 0; | |
403 new_flags = mp->flags & (FLODMAP_FG_REWINDING | |
404 | FLODMAP_FG_NEED_REWIND | |
405 | FLODMAP_FG_FFWD_IN | |
406 | FLODMAP_FG_OUT_SRVR | |
407 | FLODMAP_FG_IN_SRVR | |
408 | FLODMAP_FG_NAT_AUTO | |
409 | FLODMAP_FG_USE_2PASSWD); | |
410 | |
411 if (db_parms.flags & DB_PARM_FG_CLEARED) { | |
412 new_flags |= FLODMAP_FG_NEED_REWIND; | |
413 new_flags &= ~FLODMAP_FG_FFWD_IN; | |
414 changed = 1; | |
415 } | |
416 | |
417 if (ofp->o_opts.flags & FLOD_OPT_ROGUE) | |
418 new_flags |= FLODMAP_FG_ROGUE; | |
419 | |
420 if ((ofp->o_opts.flags & FLOD_OPT_OFF)) | |
421 new_flags |= FLODMAP_FG_OUT_OFF; | |
422 | |
423 if (ofp->i_opts.flags & FLOD_OPT_OFF) | |
424 new_flags |= FLODMAP_FG_IN_OFF; | |
425 | |
426 if (ofp->o_opts.flags & FLOD_OPT_IPv4) { | |
427 new_flags |= FLODMAP_FG_IPv4; | |
428 if (mp->flags & FLODMAP_FG_IPv6) | |
429 got_hosts = 0; | |
430 } else if (ofp->o_opts.flags & FLOD_OPT_IPv6) { | |
431 new_flags |= FLODMAP_FG_IPv6; | |
432 if (mp->flags & FLODMAP_FG_IPv4) | |
433 got_hosts = 0; | |
434 } | |
435 | |
436 if (ofp->o_opts.flags & FLOD_OPT_PASSIVE) { | |
437 new_flags |= FLODMAP_FG_PASSIVE; | |
438 } else if (ofp->o_opts.flags & FLOD_OPT_SOCKS) { | |
439 new_flags |= FLODMAP_FG_SOCKS; | |
440 } else if (ofp->o_opts.flags & FLOD_OPT_NAT) { | |
441 new_flags |= FLODMAP_FG_NAT; | |
442 } | |
443 | |
444 if (ofp->o_opts.path_len != DCC_MAX_FLOD_PATH) | |
445 new_flags |= FLODMAP_FG_LEAF; | |
446 | |
447 if (ofp->o_opts.num_maps != 0 | |
448 || ofp->i_opts.num_maps != 0) | |
449 new_flags |= FLODMAP_FG_MAPPED; | |
450 | |
451 if ((mp->flags ^ new_flags) && (FLODMAP_FG_ROGUE | |
452 | FLODMAP_FG_OUT_OFF | |
453 | FLODMAP_FG_IN_OFF | |
454 | FLODMAP_FG_IPv6 | |
455 | FLODMAP_FG_IPv4 | |
456 | FLODMAP_FG_PASSIVE | |
457 | FLODMAP_FG_SOCKS | |
458 | FLODMAP_FG_NAT | |
459 | FLODMAP_FG_LEAF | |
460 | FLODMAP_FG_MAPPED)) { | |
461 mp->flags = new_flags; | |
462 changed = 1; | |
463 } | |
464 | |
465 /* get new hostname if it changes */ | |
466 if (strcasecmp(mp->rem_hostname, ofp->rem_hostname)) { | |
467 BUFCPY(mp->rem_hostname, ofp->rem_hostname); | |
468 got_hosts = 0; /* force name resolution for new name */ | |
469 changed = 1; | |
470 } | |
471 /* always get new port name | |
472 * in case the name but not the number changes */ | |
473 BUFCPY(mp->rem_portname, ofp->rem_portname); | |
474 if (mp->rem_port != ofp->rem_port) { | |
475 mp->rem_port = ofp->rem_port; | |
476 changed = 1; | |
477 } | |
478 | |
479 if (mp->ids_mtime != ids_mtime) { | |
480 mp->ids_mtime = ids_mtime; | |
481 mp->flags &= ~FLODMAP_FG_USE_2PASSWD; | |
482 changed = 1; | |
483 } | |
484 | |
485 if (mp->in_passwd_id != ofp->in_passwd_id) { | |
486 mp->in_passwd_id = ofp->in_passwd_id; | |
487 changed = 1; | |
488 } | |
489 if (mp->out_passwd_id != ofp->out_passwd_id) { | |
490 mp->out_passwd_id = ofp->out_passwd_id; | |
491 changed = 1; | |
492 } | |
493 | |
494 if (changed) | |
495 flod_try_again(ofp); | |
496 } | |
497 | |
498 | |
499 | |
500 /* Load the hostnames of DCC server peers and their output flood positions. | |
501 * flod_names_resolve_ck() must say ok before this function is called, | |
502 * to avoid races with changing host names. | |
503 * | |
504 * Parse lines of the form | |
505 * name,port;name,port rem-ID [passwd-id [out-opts [in-opts [versionX]]]] | |
506 */ | |
507 u_char /* 1=ok to start flooding */ | |
508 load_flod(u_char complain) | |
509 { | |
510 DCC_FNM_LNO_BUF fnm_buf; | |
511 OFLOD_INFO *ofp, *ofp1; | |
512 FILE *f; | |
513 struct stat sb; | |
514 int lno; | |
515 char buf[200]; | |
516 char hostname[60]; | |
517 const char *bufp, *bufp1; | |
518 FLOD_MMAP *mp, *mp1; | |
519 union { | |
520 OFLOD_INFO info; | |
521 FLOD_MMAP map; | |
522 } swap; | |
523 const ID_TBL *tp; | |
524 char *p; | |
525 int i; | |
526 | |
527 /* the caller should use RUSH_NEXT_FLODS_CK() or similar, but | |
528 * just in case ... */ | |
529 if (!flod_names_resolve_ck()) | |
530 return 0; | |
531 | |
532 /* forget everything about flooding */ | |
533 oflods_clear(); | |
534 | |
535 /* keep the map open and locked most of the time */ | |
536 if (!flod_mmap(dcc_emsg, &db_parms.sn, &dccd_stats, 1, | |
537 (DCC_TRACE_FLOD_BIT & dccd_tracemask) != 0)) { | |
538 if (complain) | |
539 dcc_error_msg("%s", dcc_emsg); | |
540 flod_mtime = 0; | |
541 return 0; | |
542 } | |
543 | |
544 f = fopen(flod_path, "r"); | |
545 if (!f) { | |
546 if (flod_mtime != 0) { | |
547 dcc_error_msg("fopen(%s): %s", | |
548 flod_path, ERROR_STR()); | |
549 flod_mtime = 0; | |
550 } | |
551 | |
552 flod_unmap(0, &dccd_stats); | |
553 return 0; | |
554 } | |
555 if (0 > fstat(fileno(f), &sb)) { | |
556 if (flod_mtime!= 0) | |
557 dcc_error_msg("stat(%s): %s", | |
558 flod_path, ERROR_STR()); | |
559 fclose(f); | |
560 flod_unmap(0, &dccd_stats); | |
561 flod_mtime = 0; | |
562 return 0; | |
563 } | |
564 flod_mtime = sb.st_mtime; | |
565 | |
566 /* Parse the ASCII file of names and parameters first so that we do not | |
567 * destroy the position information if there is a problem with names */ | |
568 ofp = oflods.infos; | |
569 lno = 0; | |
570 for (;;) { | |
571 /* clear the entry in case we started to set it with the | |
572 * preceding line from the /var/dcc/flod file */ | |
573 if (ofp <= LAST(oflods.infos)) | |
574 oflod_clear(ofp); | |
575 | |
576 ++lno; | |
577 bufp = fgets(buf, sizeof(buf), f); | |
578 if (!bufp) { | |
579 if (ferror(f)) { | |
580 dcc_error_msg("fgets(%s): %s", | |
581 flod_path, ERROR_STR()); | |
582 break; | |
583 } | |
584 if (fclose(f) == EOF) { | |
585 dcc_error_msg("fclose(%s): %s", | |
586 flod_path, ERROR_STR()); | |
587 } | |
588 f = 0; | |
589 break; | |
590 } | |
591 i = strlen(bufp); | |
592 if (i >= ISZ(buf)-1) { | |
593 dcc_error_msg("too many characters%s", | |
594 fnm_lno(&fnm_buf, flod_path, lno)); | |
595 do { | |
596 i = getc(f); | |
597 } while (i != '\n' && i != EOF); | |
598 continue; | |
599 } | |
600 /* ignore comments */ | |
601 p = strchr(bufp, '#'); | |
602 if (p) | |
603 *p = '\0'; | |
604 else | |
605 p = &buf[i]; | |
606 /* trim trailing blanks */ | |
607 while (--p > bufp && (*p == ' ' || *p == '\t' || *p == '\n')) | |
608 *p = '\0'; | |
609 /* skip blank lines */ | |
610 bufp += strspn(bufp, DCC_WHITESPACE); | |
611 if (*bufp == '\0') | |
612 continue; | |
613 | |
614 if (oflods.total >= DIM(oflods.infos)) { | |
615 dcc_error_msg("too many DCC peers in %s; max=%d", | |
616 flod_path, DIM(oflods.infos)); | |
617 continue; | |
618 } | |
619 | |
620 ofp->lno = lno; | |
621 | |
622 /* get IP address and port number of remote DCC server */ | |
623 bufp1 = bufp+strcspn(bufp, DCC_WHITESPACE";"); | |
624 if (*bufp1 != ';') { | |
625 bufp1 = 0; | |
626 } else { | |
627 /* Allow the local or client TCP IP address and | |
628 * port number to be specified. */ | |
629 buf[bufp1++ - buf] = '\0'; | |
630 } | |
631 bufp = dcc_parse_nm_port(0, bufp, def_port, | |
632 ofp->rem_hostname, | |
633 sizeof(ofp->rem_hostname), | |
634 &ofp->rem_port, | |
635 ofp->rem_portname, | |
636 sizeof(ofp->rem_portname), | |
637 flod_path, lno); | |
638 if (!bufp) | |
639 continue; | |
640 if (bufp1) { | |
641 /* parse the local IP address first */ | |
642 bufp = dcc_parse_nm_port(0, bufp1, 0, | |
643 ofp->loc_hostname, | |
644 sizeof(ofp->loc_hostname), | |
645 &ofp->loc_port, 0, 0, | |
646 flod_path, lno); | |
647 if (!bufp) | |
648 continue; | |
649 } | |
650 | |
651 bufp = oflod_parse_id(&ofp->rem_id, bufp, | |
652 "rem-id", lno); | |
653 if (!bufp) | |
654 continue; | |
655 if (ofp->rem_id == DCC_ID_INVALID) { | |
656 dcc_error_msg("missing rem-id%s", | |
657 fnm_lno(&fnm_buf, flod_path, lno)); | |
658 continue; | |
659 } | |
660 | |
661 bufp = oflod_parse_id(&ofp->out_passwd_id, bufp, | |
662 "passwd-id", lno); | |
663 if (!bufp) | |
664 continue; | |
665 if (ofp->out_passwd_id == DCC_ID_INVALID) { | |
666 ofp->out_passwd_id = my_srvr_id; | |
667 ofp->in_passwd_id = ofp->rem_id; | |
668 } else { | |
669 ofp->in_passwd_id = ofp->out_passwd_id; | |
670 } | |
671 | |
672 ofp->oversion = DCC_FLOD_VERSION_DEF; | |
673 bufp = parse_flod_opts(ofp, &ofp->o_opts, bufp, lno); | |
674 if (!bufp) | |
675 continue; | |
676 bufp = parse_flod_opts(ofp, &ofp->i_opts, bufp, lno); | |
677 if (!bufp) | |
678 continue; | |
679 if (*bufp != '\0') | |
680 dcc_error_msg("trailing garbage \"%s\" ignored%s", | |
681 bufp, fnm_lno(&fnm_buf, flod_path, lno)); | |
682 | |
683 tp = find_srvr_type(ofp->rem_id); | |
684 if (0 < find_srvr_rcd_type(ofp->rem_id)) { | |
685 switch (DB_RCD_ID(db_sts.rcd2.d.r)) { | |
686 case DCC_ID_SRVR_REP_OK: | |
687 case DCC_ID_SRVR_SIMPLE: | |
688 ofp->o_opts.flags |= FLOD_OPT_SIMPLE; | |
689 break; | |
690 case DCC_ID_SRVR_ROGUE: | |
691 ofp->o_opts.flags |= FLOD_OPT_ROGUE; | |
692 break; | |
693 default: | |
694 dcc_error_msg("unknown state for server-ID %d", | |
695 ofp->rem_id); | |
696 break; | |
697 } | |
698 } | |
699 | |
700 /* both servers having spam traps and assuming the other | |
701 * doesn't makes no sense */ | |
702 if (((ofp->o_opts.flags & FLOD_OPT_TRAPS) | |
703 || (ofp->i_opts.flags & FLOD_OPT_TRAPS)) | |
704 && !(ofp->i_opts.flags & FLOD_OPT_OFF) | |
705 && !(ofp->o_opts.flags & FLOD_OPT_OFF)) { | |
706 dcc_error_msg("symmetric trap-only link%s", | |
707 fnm_lno(&fnm_buf, flod_path, lno)); | |
708 continue; | |
709 } | |
710 | |
711 for (ofp1 = oflods.infos; ofp1 < ofp; ++ofp1) { | |
712 if ((!strcmp(ofp1->rem_hostname, ofp->rem_hostname) | |
713 && ofp1->rem_port == ofp->rem_port) | |
714 || ofp1->rem_id == ofp->rem_id) | |
715 break; | |
716 } | |
717 if (ofp1 != ofp) { | |
718 dcc_error_msg("duplicate DCC peer%s", | |
719 fnm_lno(&fnm_buf, flod_path, lno)); | |
720 continue; | |
721 } | |
722 | |
723 /* ignore ourself */ | |
724 if (ofp->rem_id == my_srvr_id) | |
725 continue; | |
726 | |
727 ofp->limit_reset = db_time.tv_sec + FLOD_LIM_CLEAR_SECS; | |
728 | |
729 ++ofp; | |
730 ++oflods.total; | |
731 } | |
732 if (f) | |
733 fclose(f); | |
734 | |
735 /* sort new list by server-ID so that `cdcc "flood list"` is sorted */ | |
736 ofp = oflods.infos; | |
737 while (ofp < LAST(oflods.infos)) { | |
738 ofp1 = ofp+1; | |
739 if (ofp1->rem_hostname[0] == '\0') | |
740 break; | |
741 if (ofp->rem_id <= ofp1->rem_id) { | |
742 ofp = ofp1; | |
743 continue; | |
744 } | |
745 /* bubble sort because the list is usually already | |
746 * ordered and almost always tiny */ | |
747 memcpy(&swap.info, ofp1, sizeof(swap.info)); | |
748 memcpy(ofp1, ofp, sizeof(*ofp1)); | |
749 memcpy(ofp, &swap.info, sizeof(*ofp)); | |
750 ofp = oflods.infos; | |
751 } | |
752 | |
753 mp = flod_mmaps->mmaps; | |
754 | |
755 /* Bubble sort the list in the /var/dcc/flod/map file so that is | |
756 * sorted for `dblist -Hv`. The file will usually already be sorted | |
757 * and is tiny. */ | |
758 mp1 = mp+1; | |
759 while (mp1 <= LAST(flod_mmaps->mmaps)) { | |
760 if (mp1->rem_hostname[0] == '\0') { | |
761 ++mp1; | |
762 continue; | |
763 } | |
764 if (mp->rem_hostname[0] == '\0' | |
765 || mp->rem_id <= mp1->rem_id) { | |
766 mp = mp1++; | |
767 continue; | |
768 } | |
769 memcpy(&swap.map, mp1, sizeof(swap.map)); | |
770 memcpy(mp1, mp, sizeof(*mp1)); | |
771 memcpy(mp, &swap.map, sizeof(*mp)); | |
772 mp = flod_mmaps->mmaps; | |
773 mp1 = mp+1; | |
774 } | |
775 | |
776 /* combine our list that is based on the ASCII file /var/dcc/flod | |
777 * with the memory mapped /var/dcc/flod.map list of what has | |
778 * been sent to each peer */ | |
779 for (mp = flod_mmaps->mmaps; mp <= LAST(flod_mmaps->mmaps); ++mp) | |
780 mp->flags &= ~FLODMAP_FG_MARK; | |
781 | |
782 /* make one pass matching old names with their slots in the | |
783 * mapped file */ | |
784 mp = flod_mmaps->mmaps; | |
785 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) { | |
786 if (ofp->rem_hostname[0] == '\0') | |
787 break; | |
788 for (i = 0; i < DIM(flod_mmaps->mmaps); ++i) { | |
789 if (++mp > LAST(flod_mmaps->mmaps)) | |
790 mp = flod_mmaps->mmaps; | |
791 if (mp->rem_hostname[0] == '\0') | |
792 continue; | |
793 if (!(mp->flags & FLODMAP_FG_MARK) | |
794 && ofp->rem_id == mp->rem_id) { | |
795 /* found the old slot */ | |
796 if (DB_PTR_IS_BAD(mp->confirm_pos) | |
797 || mp->confirm_pos > db_csize) { | |
798 dcc_error_msg("bogus position "L_HPAT | |
799 " for %s in %s", | |
800 mp->confirm_pos, | |
801 ofp->rem_hostname, | |
802 flod_mmap_path); | |
803 mp->rem_hostname[0] = '\0'; | |
804 continue; | |
805 } | |
806 ofp->cur_pos = mp->confirm_pos; | |
807 ofp->rewind_pos = db_csize; | |
808 ofp->mp = mp; | |
809 copy_opts2mp(ofp); | |
810 mp->flags |= FLODMAP_FG_MARK; | |
811 break; | |
812 } | |
813 } | |
814 } | |
815 | |
816 | |
817 /* use a free or obsolete slot in the mapped file for new entries */ | |
818 mp = flod_mmaps->mmaps; | |
819 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) { | |
820 /* find the next new peer without a mapped file slot */ | |
821 if (ofp->rem_hostname[0] == '\0') | |
822 break; | |
823 if (ofp->mp != 0) | |
824 continue; | |
825 | |
826 /* find a free or no longer used slot */ | |
827 while (mp->flags & FLODMAP_FG_MARK) { | |
828 if (++mp > LAST(flod_mmaps->mmaps)) { | |
829 bad_stop("too few oflod mmap slots"); | |
830 goto out; | |
831 } | |
832 } | |
833 if (mp->rem_hostname[0] != '\0') | |
834 dcc_error_msg("forget flood to %s %d", | |
835 dcc_host_portname(hostname, | |
836 sizeof(hostname), | |
837 mp->rem_hostname, | |
838 mp->rem_portname), | |
839 mp->rem_id); | |
840 | |
841 /* we have found a free slot */ | |
842 memset(mp, 0, sizeof(*mp)); | |
843 ofp->mp = mp; | |
844 mp->rem_su.sa.sa_family = AF_UNSPEC; | |
845 mp->rem_id = ofp->rem_id; | |
846 copy_opts2mp(ofp); | |
847 | |
848 mp->cnts.cnts_cleared = db_time.tv_sec; | |
849 | |
850 if (flod_mmaps->delay_pos < DB_PTR_BASE) { | |
851 /* do not rewind if repairing a broken file */ | |
852 ofp->cur_pos = mp->confirm_pos = db_csize; | |
853 ofp->recv_pos = ofp->xmit_pos = db_csize; | |
854 } else { | |
855 ofp->cur_pos = mp->confirm_pos = DB_PTR_BASE; | |
856 ofp->recv_pos = ofp->xmit_pos = DB_PTR_BASE; | |
857 } | |
858 | |
859 mp->flags |= FLODMAP_FG_MARK; | |
860 | |
861 dcc_error_msg("initialize flood to %s %d%s", | |
862 dcc_host_portname(hostname, sizeof(hostname), | |
863 mp->rem_hostname, | |
864 mp->rem_portname), | |
865 mp->rem_id, | |
866 fnm_lno(&fnm_buf, flod_path, ofp->lno)); | |
867 } | |
868 out:; | |
869 | |
870 /* clear the slots that contain forgotten hosts */ | |
871 for (mp = flod_mmaps->mmaps; mp <= LAST(flod_mmaps->mmaps); ++mp) { | |
872 if (!(mp->flags & FLODMAP_FG_MARK)) { | |
873 if (mp->rem_hostname[0] != '\0') | |
874 dcc_error_msg("forget flood to %s %d", | |
875 dcc_host_portname(hostname, | |
876 sizeof(hostname), | |
877 mp->rem_hostname, | |
878 mp->rem_portname), | |
879 mp->rem_id); | |
880 memset(mp, 0, sizeof(*mp)); | |
881 } | |
882 } | |
883 | |
884 flod_mmap_sync(0, 1); | |
885 | |
886 db_parms.flags &= ~DB_PARM_FG_CLEARED; | |
887 db_flush_parms(0); | |
888 | |
889 get_oflods_max_cur_pos(); | |
890 return 1; | |
891 } | |
892 | |
893 | |
894 | |
895 /* put the flood counters in stable storage */ | |
896 void | |
897 save_flod_cnts(OFLOD_INFO *ofp) | |
898 { | |
899 FLOD_MMAP *mp; | |
900 time_t delta; | |
901 FLOD_LIMCNT *lc; | |
902 | |
903 dccd_stats.iflod_total += ofp->cnts.total; | |
904 dccd_stats.iflod_accepted += ofp->cnts.accepted; | |
905 dccd_stats.iflod_stale += ofp->lc.stale.cur; | |
906 dccd_stats.iflod_dup += ofp->lc.dup.cur; | |
907 dccd_stats.iflod_wlist += ofp->lc.wlist.cur; | |
908 dccd_stats.iflod_not_deleted += ofp->lc.not_deleted.cur; | |
909 | |
910 mp = ofp->mp; | |
911 if (mp) { | |
912 if (ofp->xmit_pos == ofp->recv_pos) | |
913 ofp->mp->confirm_pos = ofp->cur_pos; | |
914 | |
915 mp->cnts.total += ofp->cnts.total; | |
916 mp->cnts.accepted += ofp->cnts.accepted; | |
917 mp->cnts.stale += ofp->lc.stale.cur; | |
918 mp->cnts.dup += ofp->lc.dup.cur; | |
919 mp->cnts.wlist += ofp->lc.wlist.cur; | |
920 mp->cnts.not_deleted += ofp->lc.not_deleted.cur; | |
921 | |
922 mp->cnts.out_reports += ofp->cnts.out_reports; | |
923 | |
924 delta = db_time.tv_sec - ofp->cnts.saved; | |
925 if (delta < 0) | |
926 delta = 0; | |
927 if (ofp->ifp) { | |
928 if (mp->flags & FLODMAP_FG_IN_CONN) { | |
929 mp->cnts.in_total_conn += delta; | |
930 } else { | |
931 mp->flags |= FLODMAP_FG_IN_CONN; | |
932 mp->cnts.in_conn_changed = db_time.tv_sec; | |
933 } | |
934 } else { | |
935 if (mp->flags & FLODMAP_FG_IN_CONN) { | |
936 mp->flags &= ~FLODMAP_FG_IN_CONN; | |
937 mp->cnts.in_conn_changed = db_time.tv_sec; | |
938 } | |
939 } | |
940 | |
941 if (ofp->flags & OFLOD_FG_CONNECTED) { | |
942 if (mp->flags & FLODMAP_FG_OUT_CONN) { | |
943 mp->cnts.out_total_conn += delta; | |
944 } else { | |
945 mp->flags |= FLODMAP_FG_OUT_CONN; | |
946 mp->cnts.out_conn_changed = db_time.tv_sec; | |
947 } | |
948 } else { | |
949 if (mp->flags & FLODMAP_FG_OUT_CONN) { | |
950 mp->flags &= ~FLODMAP_FG_OUT_CONN; | |
951 mp->cnts.out_conn_changed = db_time.tv_sec; | |
952 } | |
953 } | |
954 } | |
955 | |
956 memset(&ofp->cnts, 0, sizeof(ofp->cnts)); | |
957 for (lc = (FLOD_LIMCNT *)&ofp->lc; | |
958 lc < (FLOD_LIMCNT *)(sizeof(ofp->lc)+(char *)&ofp->lc); | |
959 ++lc) { | |
960 lc->lim -= lc->cur; | |
961 lc->cur = 0; | |
962 } | |
963 | |
964 ofp->cnts.saved = db_time.tv_sec; | |
965 } | |
966 | |
967 | |
968 | |
969 void | |
970 oflod_close(OFLOD_INFO *ofp, u_char fail) | |
971 { | |
972 u_char need_oflods_clear = 0; | |
973 | |
974 if (ofp->rem_hostname[0] == '\0') | |
975 return; | |
976 | |
977 if (ofp->soc >= 0) { | |
978 if (0 > close(ofp->soc) | |
979 && !fail) { | |
980 if (errno == ECONNRESET) | |
981 TMSG2_FLOD(ofp, "close(flood to %s): %s", | |
982 ofp_rem_str(ofp), ERROR_STR()); | |
983 else | |
984 dcc_error_msg("close(flod to %s): %s", | |
985 ofp_rem_str(ofp), ERROR_STR()); | |
986 } | |
987 ofp->soc = -1; | |
988 ofp->flags &= ~(OFLOD_FG_CONNECTED | |
989 | OFLOD_FG_SHUTDOWN_REQ | |
990 | OFLOD_FG_SHUTDOWN); | |
991 ofp->obuf_len = 0; | |
992 ofp->cnts.out_reports = 0; | |
993 | |
994 save_flod_cnts(ofp); | |
995 | |
996 if (--oflods.open == 0 | |
997 && iflods.open == 0 | |
998 && flods_st != FLODS_ST_ON) | |
999 need_oflods_clear = 1; | |
1000 } | |
1001 | |
1002 if (fail) { | |
1003 if (ofp->mp->otimers.retry_secs < FLOD_RETRY_SECS/2) | |
1004 ofp->mp->otimers.retry_secs = FLOD_RETRY_SECS/2; | |
1005 ofp->mp->otimers.retry = (db_time.tv_sec | |
1006 + ofp->mp->otimers.retry_secs); | |
1007 if (!(ofp->mp->flags & FLODMAP_FG_PASSIVE)) | |
1008 TMSG2_FLOD(ofp, | |
1009 "postpone restarting flood to %s" | |
1010 " for %d seconds", | |
1011 ofp_rem_str(ofp), | |
1012 ofp->mp->otimers.retry_secs); | |
1013 } | |
1014 | |
1015 if (need_oflods_clear) | |
1016 oflods_clear(); | |
1017 } | |
1018 | |
1019 | |
1020 | |
1021 /* get ready to shut down */ | |
1022 static void | |
1023 start_shutdown(OFLOD_INFO *ofp) | |
1024 { | |
1025 if (ofp->flags & (OFLOD_FG_SHUTDOWN_REQ | |
1026 | OFLOD_FG_SHUTDOWN)) | |
1027 return; | |
1028 | |
1029 /* arrange to ask the peer to ask us to stop */ | |
1030 ofp->flags |= OFLOD_FG_SHUTDOWN_REQ; | |
1031 ofp->flags &= ~OFLOD_FG_NEW; | |
1032 oflod_fill(ofp); | |
1033 | |
1034 /* oflod_write() might set this again, but that will either be soon | |
1035 * or a good thing if delayed */ | |
1036 ofp->oflod_alive = db_time.tv_sec; | |
1037 } | |
1038 | |
1039 | |
1040 | |
1041 /* Half-close the TCP connection. | |
1042 * The other DCC server will notice and send our final position | |
1043 * to acknowledge dealing with our reports. */ | |
1044 static void | |
1045 oflod_shutdown(OFLOD_INFO *ofp) | |
1046 { | |
1047 struct linger nowait; | |
1048 | |
1049 /* wait until the output buffer is empty */ | |
1050 if (ofp->obuf_len != 0) | |
1051 return; | |
1052 | |
1053 /* do it only once */ | |
1054 if ((ofp->flags & OFLOD_FG_SHUTDOWN)) | |
1055 return; | |
1056 ofp->flags |= OFLOD_FG_SHUTDOWN; | |
1057 | |
1058 /* on Solaris and Linux you must set SO_LINGER before shutdown() */ | |
1059 nowait.l_onoff = 1; | |
1060 nowait.l_linger = SHUTDOWN_DELAY; | |
1061 if (0 > setsockopt(ofp->soc, SOL_SOCKET, SO_LINGER, | |
1062 &nowait, sizeof(nowait))) | |
1063 rpt_err(ofp, 0, 0, | |
1064 "setsockopt(SO_LINGER flood to %s): %s", | |
1065 ofp_rem_str(ofp), ERROR_STR()); | |
1066 | |
1067 if (0 > shutdown(ofp->soc, 1)) { | |
1068 rpt_err(ofp, errno == ECONNRESET, 0, | |
1069 "shutdown(flood to %s): %s", | |
1070 ofp_rem_str(ofp), ERROR_STR()); | |
1071 oflod_close(ofp, 1); | |
1072 } | |
1073 } | |
1074 | |
1075 | |
1076 | |
1077 /* see if a report should be put into the output buffer for a flood | |
1078 * db_sts.rcd.d.r points to the current record. | |
1079 * ofp->cur_pos has already been advanced */ | |
1080 static u_char /* 1=flood this report, 0=don't */ | |
1081 oflod_ck_put(void) | |
1082 { | |
1083 const DB_RCD_CK *cur_rcd_ck; | |
1084 DCC_TGTS rcd_tgts, ck_tgts; | |
1085 int num_cks; | |
1086 DCC_CK_TYPES type; | |
1087 u_char obs_lvl, result; | |
1088 | |
1089 /* skip padding, whitelisted, compressed, trimmed | |
1090 * and deleted entries */ | |
1091 if (DB_RCD_ID(db_sts.rcd.d.r) == DCC_ID_WHITE | |
1092 || DB_RCD_ID(db_sts.rcd.d.r) == DCC_ID_COMP | |
1093 || (rcd_tgts = DB_TGTS_RCD_RAW(db_sts.rcd.d.r)) == 0 | |
1094 || DB_RCD_TRIMMED(db_sts.rcd.d.r)) | |
1095 return 0; | |
1096 | |
1097 /* Skip reports that should not be flooded yet | |
1098 * The flooding thresholds are used to set the delay flag. | |
1099 * Small reports are marked with the delay flag when they are added | |
1100 * to the database. If later it seems they should be flooded, | |
1101 * they are summarized in a new report that is flooded. */ | |
1102 if (DB_RCD_DELAY(db_sts.rcd.d.r)) | |
1103 return 0; | |
1104 | |
1105 result = 0; | |
1106 obs_lvl = 0; | |
1107 cur_rcd_ck = db_sts.rcd.d.r->cks; | |
1108 for (num_cks = DB_NUM_CKS(db_sts.rcd.d.r); | |
1109 num_cks != 0; | |
1110 ++cur_rcd_ck, --num_cks) { | |
1111 type = DB_CK_TYPE(cur_rcd_ck); | |
1112 | |
1113 /* ignore junk for deciding whether we can send this report. */ | |
1114 if (DB_TEST_NOKEEP(db_parms.nokeep_cks, type)) | |
1115 continue; | |
1116 | |
1117 if (DB_CK_OBS(cur_rcd_ck)) { | |
1118 /* an obsolete fuzzier checksum | |
1119 * makes less fuzzy checksums obsolete */ | |
1120 if (obs_lvl < db_ck_fuzziness[type]) { | |
1121 obs_lvl = db_ck_fuzziness[type]; | |
1122 result = 0; | |
1123 } | |
1124 continue; | |
1125 } | |
1126 | |
1127 /* send server-ID declarations | |
1128 * unless they are delete requests */ | |
1129 if (type == DCC_CK_SRVR_ID) { | |
1130 if (rcd_tgts == DCC_TGTS_DEL) | |
1131 continue; | |
1132 return 1; | |
1133 } | |
1134 | |
1135 /* do not send whitelisted reports */ | |
1136 ck_tgts = DB_TGTS_CK(cur_rcd_ck); | |
1137 if (ck_tgts == DCC_TGTS_OK || ck_tgts == DCC_TGTS_OK2) | |
1138 return 0; | |
1139 | |
1140 /* send non-obsolete results */ | |
1141 if (obs_lvl <= db_ck_fuzziness[type]) { | |
1142 obs_lvl = db_ck_fuzziness[type]; | |
1143 result = 1; | |
1144 } | |
1145 } | |
1146 return result; | |
1147 } | |
1148 | |
1149 | |
1150 | |
1151 /* put report into the output buffer for a flood if appropriate | |
1152 * db_sts.rcd.d.r points to the current record. | |
1153 * ofp->cur_pos has already been advanced */ | |
1154 static void | |
1155 put_rcd_obuf(OFLOD_INFO *ofp, const DB_RCD *cur_rcd) | |
1156 { | |
1157 DCC_FLOD_RPT *rp; | |
1158 DCC_TGTS tgts; | |
1159 DCC_SRVR_ID srvr, psrvr; | |
1160 const DB_RCD_CK *cur_rcd_ck; | |
1161 DCC_CK *buf_ck; | |
1162 DCC_FLOD_PATH_ID *new_path_idp, *new_path_id_limp, *rcd_path_id; | |
1163 int path_id_max; | |
1164 DCC_CK_TYPES type; | |
1165 ID_MAP_RESULT srvr_mapped; | |
1166 u_char reflecting; /* 1=report is pointed at its source */ | |
1167 u_char non_path, all_spam; | |
1168 int num_cks, j; | |
1169 | |
1170 /* decide whether to send this report */ | |
1171 if (!oflod_ck_put()) | |
1172 return; /* skip it */ | |
1173 | |
1174 rp = (DCC_FLOD_RPT *)&ofp->obuf.b[ofp->obuf_len]; | |
1175 db_ptr2flod_pos(rp->pos, ofp->cur_pos); | |
1176 tgts = DB_TGTS_RCD_RAW(cur_rcd); | |
1177 if (tgts == DCC_TGTS_DEL) { | |
1178 /* don't send delete requests to systems that don't want them */ | |
1179 if (!(ofp->o_opts.flags & FLOD_OPT_DEL_OK)) | |
1180 return; | |
1181 } else if (ofp->o_opts.flags & FLOD_OPT_TRAPS) { | |
1182 tgts = DCC_TGTS_TOO_MANY; | |
1183 } | |
1184 | |
1185 srvr = DB_RCD_ID(cur_rcd); | |
1186 /* translate the source server-ID */ | |
1187 srvr_mapped = id_map(srvr, &ofp->o_opts); | |
1188 switch (srvr_mapped) { | |
1189 case ID_MAP_NO: | |
1190 break; | |
1191 case ID_MAP_REJ: | |
1192 return; | |
1193 case ID_MAP_SELF: | |
1194 srvr = my_srvr_id; | |
1195 break; | |
1196 } | |
1197 /* this loses the DCC_SRVR_ID_AUTH bit */ | |
1198 rp->srvr_id_auth[0] = srvr>>8; | |
1199 rp->srvr_id_auth[1] = srvr; | |
1200 | |
1201 reflecting = (srvr == ofp->rem_id); | |
1202 non_path = 0; | |
1203 | |
1204 rp->ts = cur_rcd->ts; | |
1205 | |
1206 cur_rcd_ck = cur_rcd->cks; | |
1207 | |
1208 /* Add a path if we are not the source of the report | |
1209 * or if it already has a path */ | |
1210 buf_ck = rp->cks; | |
1211 if (srvr != my_srvr_id | |
1212 || DB_CK_TYPE(cur_rcd_ck) == DCC_CK_FLOD_PATH) { | |
1213 /* Add a checksum entry for a path consisting of only our | |
1214 * server-ID. If the report contains a path, we will | |
1215 * concatenate to this entry */ | |
1216 memset(buf_ck, 0, sizeof(*buf_ck)); | |
1217 buf_ck->len = sizeof(*buf_ck); | |
1218 buf_ck->type = DCC_CK_FLOD_PATH; | |
1219 new_path_idp = (DCC_FLOD_PATH_ID *)buf_ck->sum; | |
1220 new_path_idp->hi = my_srvr_id>>8; | |
1221 new_path_idp->lo = my_srvr_id; | |
1222 new_path_id_limp = new_path_idp + DCC_NUM_FLOD_PATH; | |
1223 path_id_max = ofp->o_opts.path_len-1; | |
1224 ++new_path_idp; | |
1225 ++buf_ck; | |
1226 rp->num_cks = 1; | |
1227 } else { | |
1228 /* do not add a path */ | |
1229 new_path_idp = new_path_id_limp = 0; | |
1230 path_id_max = 0; | |
1231 rp->num_cks = 0; | |
1232 } | |
1233 | |
1234 all_spam = 1; | |
1235 for (num_cks = DB_NUM_CKS(cur_rcd); | |
1236 num_cks != 0; | |
1237 ++cur_rcd_ck, --num_cks) { | |
1238 type = DB_CK_TYPE(cur_rcd_ck); | |
1239 if (type == DCC_CK_FLOD_PATH) { | |
1240 rcd_path_id = (DCC_FLOD_PATH_ID *)&cur_rcd_ck->sum; | |
1241 for (j = 0; j < DCC_NUM_FLOD_PATH; ++j, ++rcd_path_id) { | |
1242 psrvr = ((rcd_path_id->hi<<8) | |
1243 | rcd_path_id->lo); | |
1244 /* stop copying the path at its end */ | |
1245 if (psrvr == DCC_ID_INVALID) | |
1246 break; | |
1247 /* don't send report if its path is too long */ | |
1248 if (--path_id_max < 0) | |
1249 return; | |
1250 /* add another "checksum" to continue path */ | |
1251 if (new_path_idp >= new_path_id_limp) { | |
1252 memset(buf_ck, 0, sizeof(*buf_ck)); | |
1253 buf_ck->len = sizeof(*buf_ck); | |
1254 buf_ck->type = DCC_CK_FLOD_PATH; | |
1255 new_path_idp = (DCC_FLOD_PATH_ID * | |
1256 )buf_ck->sum; | |
1257 new_path_id_limp = (new_path_idp | |
1258 + DCC_NUM_FLOD_PATH); | |
1259 ++buf_ck; | |
1260 ++rp->num_cks; | |
1261 } | |
1262 /* Do not send reports from the target back | |
1263 * to the target unless the report is a | |
1264 * server-ID declaration */ | |
1265 if (psrvr == ofp->rem_id) | |
1266 reflecting = 1; | |
1267 switch (id_map(psrvr, &ofp->o_opts)) { | |
1268 case ID_MAP_NO: | |
1269 break; | |
1270 case ID_MAP_REJ: | |
1271 return; | |
1272 case ID_MAP_SELF: | |
1273 psrvr = my_srvr_id; | |
1274 break; | |
1275 } | |
1276 new_path_idp->hi = psrvr>>8; | |
1277 new_path_idp->lo = psrvr; | |
1278 ++new_path_idp; | |
1279 } | |
1280 | |
1281 } else { | |
1282 /* Do not send translated server-ID declarations | |
1283 * or checksums in our own or in translated server-ID | |
1284 * reports that we wouldn't have kept if we had | |
1285 * received the original reports */ | |
1286 if (srvr_mapped == ID_MAP_SELF) { | |
1287 if (type == DCC_CK_SRVR_ID) | |
1288 return; | |
1289 if (DB_TEST_NOKEEP(db_parms.nokeep_cks, type)) | |
1290 continue; | |
1291 } | |
1292 /* Do not send reports from the target to the target | |
1293 * unless the report is a Server-ID declaration */ | |
1294 if (reflecting && type != DCC_CK_SRVR_ID) | |
1295 return; | |
1296 | |
1297 /* send everything else */ | |
1298 buf_ck->type = type; | |
1299 buf_ck->len = sizeof(*buf_ck); | |
1300 memcpy(buf_ck->sum, cur_rcd_ck->sum, | |
1301 sizeof(buf_ck->sum)); | |
1302 ++buf_ck; | |
1303 ++rp->num_cks; | |
1304 | |
1305 non_path = 1; | |
1306 if (all_spam | |
1307 && DB_TGTS_CK(cur_rcd_ck) != DCC_TGTS_TOO_MANY) | |
1308 all_spam = 0; | |
1309 } | |
1310 } | |
1311 | |
1312 /* quit if we found nothing but the path to send */ | |
1313 if (!non_path) | |
1314 return; | |
1315 | |
1316 if (all_spam && srvr == my_srvr_id) | |
1317 tgts = DCC_TGTS_TOO_MANY; | |
1318 tgts = htonl(tgts); | |
1319 memcpy(&rp->tgts, &tgts, sizeof(rp->tgts)); | |
1320 | |
1321 ofp->obuf_len += (char *)buf_ck - (char *)rp; | |
1322 ++ofp->cnts.out_reports; | |
1323 ofp->xmit_pos = ofp->cur_pos; | |
1324 } | |
1325 | |
1326 | |
1327 | |
1328 /* send reports from the database to a peer DCC server | |
1329 * This routine only fills the buffer. The buffer is eventually | |
1330 * written by oflod_write(). */ | |
1331 static void | |
1332 oflod_fill(OFLOD_INFO *ofp) | |
1333 { | |
1334 int cur_rcd_len; | |
1335 | |
1336 /* stop when things are not ready or shutting down */ | |
1337 if (!(ofp->flags & OFLOD_FG_CONNECTED) | |
1338 || (ofp->flags & OFLOD_FG_SHUTDOWN) | |
1339 || (ofp->flags & OFLOD_FG_NEW)) | |
1340 return; | |
1341 | |
1342 /* stop when we are about to clean the database for a deletion so | |
1343 * that we will not be shut down cleaning along with our neighbors */ | |
1344 if (need_del_dbclean) | |
1345 return; | |
1346 | |
1347 if (db_failed_line) | |
1348 return; | |
1349 | |
1350 while (ofp->obuf_len < sizeof(ofp->obuf) - sizeof(DCC_FLOD_RPT)) { | |
1351 /* start a new entry unless we are shutting down */ | |
1352 if (ofp->flags & OFLOD_FG_SHUTDOWN_REQ) { | |
1353 oflod_shutdown(ofp); | |
1354 break; | |
1355 } | |
1356 | |
1357 if (ofp->cur_pos >= db_csize) { | |
1358 /* nothing to send | |
1359 * shut down if needed */ | |
1360 if (ofp->xmit_pos == ofp->recv_pos) | |
1361 ofp->mp->confirm_pos = ofp->cur_pos; | |
1362 if (ofp->mp->confirm_pos >= ofp->rewind_pos) | |
1363 ofp->mp->flags &= ~FLODMAP_FG_REWINDING; | |
1364 break; | |
1365 } | |
1366 | |
1367 /* don't try to look at reports crossing page bounardies */ | |
1368 if (ofp->cur_pos%db_pagesize >= db_page_max) { | |
1369 ofp->cur_pos += DB_RCD_HDR_LEN; | |
1370 continue; | |
1371 } | |
1372 | |
1373 if (!db_map_rcd(dcc_emsg, &db_sts.rcd, ofp->cur_pos, | |
1374 &cur_rcd_len)) { | |
1375 dcc_error_msg("oflod_fill() starting at "L_HPAT | |
1376 " for %s: %s", | |
1377 ofp->cur_pos, ofp_rem_str(ofp), dcc_emsg); | |
1378 ofp->cur_pos = db_csize; | |
1379 break; | |
1380 } | |
1381 | |
1382 if (DB_NUM_CKS(db_sts.rcd.d.r) > DCC_DIM_CKS) { | |
1383 dcc_error_msg("impossible %d checksums in "L_HPAT, | |
1384 DB_NUM_CKS(db_sts.rcd.d.r), | |
1385 ofp->cur_pos); | |
1386 ofp->cur_pos = db_csize; | |
1387 break; | |
1388 } | |
1389 | |
1390 /* send the record */ | |
1391 ofp->cur_pos += cur_rcd_len; | |
1392 put_rcd_obuf(ofp, db_sts.rcd.d.r); | |
1393 } | |
1394 | |
1395 if (oflods_max_cur_pos < ofp->cur_pos) | |
1396 oflods_max_cur_pos = ofp->cur_pos; | |
1397 } | |
1398 | |
1399 | |
1400 | |
1401 /* figure out what version to tell the peer */ | |
1402 const char * | |
1403 version_str(OFLOD_INFO *ofp) | |
1404 { | |
1405 if (ofp->oversion == 0) | |
1406 return DCC_FLOD_VERSION_CUR_STR; | |
1407 #ifdef DCC_FLOD_VERSION7 | |
1408 if (ofp->oversion == DCC_FLOD_VERSION7) | |
1409 return DCC_FLOD_VERSION_CUR_STR; | |
1410 #endif | |
1411 dcc_logbad(EX_SOFTWARE, "unknown ofp->oversion=%d", | |
1412 ofp->oversion); | |
1413 } | |
1414 | |
1415 | |
1416 | |
1417 /* reset connect() or daily complaint timers and keep backoffs steady */ | |
1418 void | |
1419 flod_try_again(OFLOD_INFO *ofp) | |
1420 { | |
1421 FLOD_MMAP *mp = ofp->mp; | |
1422 | |
1423 mp = ofp->mp; | |
1424 if (!mp) | |
1425 return; | |
1426 | |
1427 /* ordinary connect() timer should fire immediately */ | |
1428 mp->otimers.retry_secs /= 2; | |
1429 mp->otimers.retry = 0; | |
1430 | |
1431 /* delay complaints for passive connections */ | |
1432 if (DCC_IS_TIME(db_time.tv_sec+FLOD_IN_COMPLAIN_NOW, | |
1433 mp->otimers.msg, mp->otimers.msg_secs)) { | |
1434 mp->otimers.msg_secs = FLOD_IN_COMPLAIN_NOW; | |
1435 mp->otimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN_NOW; | |
1436 } | |
1437 | |
1438 mp->oflod_err.msg[0] = '\0'; | |
1439 mp->oflod_err.trace_msg[0] = '\0'; | |
1440 | |
1441 /* give the peer a chance to connect to us */ | |
1442 mp->itimers.retry_secs /= 2; | |
1443 if (mp->itimers.retry_secs < FLOD_SOCKS_SOCKS_IRETRY) | |
1444 mp->itimers.retry_secs = FLOD_SOCKS_SOCKS_IRETRY; | |
1445 mp->itimers.retry = db_time.tv_sec + FLOD_SOCKS_SOCKS_IRETRY; | |
1446 | |
1447 if (DCC_IS_TIME(db_time.tv_sec+FLOD_IN_COMPLAIN_NOW, | |
1448 mp->itimers.msg, mp->itimers.msg_secs)) { | |
1449 mp->itimers.msg_secs = FLOD_IN_COMPLAIN_NOW; | |
1450 mp->itimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN_NOW; | |
1451 } | |
1452 | |
1453 mp->iflod_err.msg[0] = '\0'; | |
1454 mp->iflod_err.trace_msg[0] = '\0'; | |
1455 } | |
1456 | |
1457 | |
1458 | |
1459 /* authenticate the outgoing start of a flood */ | |
1460 const char * /* error message */ | |
1461 flod_sign(OFLOD_INFO *ofp, u_char in, void *buf, int buf_len) | |
1462 { | |
1463 const ID_TBL *tp; | |
1464 | |
1465 tp = find_id_tbl(ofp->out_passwd_id); | |
1466 if (!tp) | |
1467 return DCC_FLOD_PASSWD_ID_MSG; | |
1468 if (tp->cur_passwd[0] == '\0') | |
1469 return "no password for passwd-ID"; | |
1470 | |
1471 if (tp->next_passwd[0] != '\0') { | |
1472 ofp->flags |= OFLOD_FG_HAVE_2PASSWD; | |
1473 } else { | |
1474 ofp->flags &= ~OFLOD_FG_HAVE_2PASSWD; | |
1475 ofp->mp->flags &= ~FLODMAP_FG_USE_2PASSWD; | |
1476 } | |
1477 if (ofp->mp->flags & FLODMAP_FG_USE_2PASSWD) { | |
1478 if (in) | |
1479 ofp->flags |= OFLOD_FG_I_USED_2PASSWD; | |
1480 else | |
1481 ofp->flags |= OFLOD_FG_O_USED_2PASSWD; | |
1482 TMSG1_FLOD(ofp, "try 2nd password to %s", ofp_rem_str(ofp)); | |
1483 dcc_sign(tp->next_passwd, sizeof(tp->next_passwd), | |
1484 buf, buf_len); | |
1485 } else { | |
1486 if (in) | |
1487 ofp->flags &= ~OFLOD_FG_I_USED_2PASSWD; | |
1488 else | |
1489 ofp->flags &= ~OFLOD_FG_O_USED_2PASSWD; | |
1490 dcc_sign(tp->cur_passwd, sizeof(tp->cur_passwd), | |
1491 buf, buf_len); | |
1492 } | |
1493 return 0; | |
1494 } | |
1495 | |
1496 | |
1497 | |
1498 /* finish connecting output flood by sending our version number and signature | |
1499 * to authenticate ourself */ | |
1500 u_char /* 1=ok, 0=close output stream */ | |
1501 oflod_connect_fin(OFLOD_INFO *ofp) | |
1502 { | |
1503 DCC_SRVR_ID id; | |
1504 DCC_FNM_LNO_BUF fnm_buf; | |
1505 const char *emsg; | |
1506 | |
1507 ofp->oflod_alive = db_time.tv_sec; | |
1508 ofp->flags |= (OFLOD_FG_CONNECTED | OFLOD_FG_NEW); | |
1509 save_flod_cnts(ofp); | |
1510 | |
1511 ofp->recv_pos = ofp->xmit_pos = ofp->cur_pos = ofp->mp->confirm_pos; | |
1512 get_oflods_max_cur_pos(); | |
1513 | |
1514 ofp->ibuf_len = 0; | |
1515 | |
1516 /* convince the peer we're sane by sending our version string */ | |
1517 ofp->obuf_len = sizeof(ofp->obuf.s.v); | |
1518 memset(&ofp->obuf.s.v, 0, sizeof(ofp->obuf.s.v)); | |
1519 strcpy(ofp->obuf.s.v.body.str, version_str(ofp)); | |
1520 id = htons(my_srvr_id); | |
1521 memcpy(ofp->obuf.s.v.body.sender_srvr_id, &id, | |
1522 sizeof(ofp->obuf.s.v.body.sender_srvr_id)); | |
1523 | |
1524 emsg = flod_sign(ofp, 0, &ofp->obuf.s.v, ofp->obuf_len); | |
1525 if (emsg) { | |
1526 rpt_err(ofp, 0, 0, "%s %d%s", | |
1527 emsg, ofp->out_passwd_id, | |
1528 fnm_lno(&fnm_buf, flod_path, ofp->lno)); | |
1529 return 0; | |
1530 } | |
1531 | |
1532 TMSG1_FLOD(ofp, "start flood to %s", ofp_rem_str(ofp)); | |
1533 | |
1534 /* all is well, so forget old complaints */ | |
1535 if (!(ofp->mp->flags & FLODMAP_FG_OUT_SRVR)) { | |
1536 ofp->mp->oflod_err.msg[0] = '\0'; | |
1537 ofp->mp->oflod_err.trace_msg[0] = '\0'; | |
1538 } | |
1539 | |
1540 oflod_write(ofp); /* send our authentication */ | |
1541 | |
1542 return 1; | |
1543 } | |
1544 | |
1545 | |
1546 | |
1547 static void | |
1548 oflod_backoff(OFLOD_INFO *ofp, u_char fast) | |
1549 { | |
1550 FLOD_MMAP *mp; | |
1551 int max; | |
1552 | |
1553 mp = ofp->mp; | |
1554 mp->otimers.retry_secs *= 2; | |
1555 max = fast ? FLOD_SUBMAX_RETRY_SECS : FLOD_MAX_RETRY_SECS; | |
1556 if (mp->otimers.retry_secs > max) | |
1557 mp->otimers.retry_secs = max; | |
1558 else if (mp->otimers.retry_secs < FLOD_RETRY_SECS) | |
1559 mp->otimers.retry_secs = FLOD_RETRY_SECS; | |
1560 } | |
1561 | |
1562 | |
1563 | |
1564 /* start to connect an out-going flood */ | |
1565 static int /* -1=failure, 0=not yet, 1=done */ | |
1566 oflod_connect_start(OFLOD_INFO *ofp, const char *syscall_name) | |
1567 { | |
1568 DCC_FNM_LNO_BUF fnm_buf; | |
1569 int i; | |
1570 | |
1571 ofp->mp->flags &= ~FLODMAP_FG_OUT_SRVR; | |
1572 | |
1573 if (ofp->o_opts.flags & FLOD_OPT_SOCKS) { | |
1574 i = Rconnect(ofp->soc, &ofp->rem_su.sa, | |
1575 DCC_SU_LEN(&ofp->rem_su)); | |
1576 } else { | |
1577 /* must be NAT */ | |
1578 i = connect(ofp->soc, &ofp->rem_su.sa, | |
1579 DCC_SU_LEN(&ofp->rem_su)); | |
1580 } | |
1581 if (0 > i && errno != EISCONN) { | |
1582 if (errno == EAGAIN | |
1583 || errno == EINPROGRESS | |
1584 || errno == EALREADY) { | |
1585 rpt_err(ofp, 1, 0, "starting flood to %s", | |
1586 ofp_rem_str(ofp)); | |
1587 return 0; | |
1588 } | |
1589 | |
1590 /* Several UNIX-like systems return EINVAL for the second | |
1591 * connect() after a Unreachable ICMP message or timeout. | |
1592 * It is lame to obscure the real errno, but it is worse | |
1593 * to worry users and deal with their concerns. */ | |
1594 rpt_err(ofp, | |
1595 (errno == EINVAL || errno == ECONNABORTED | |
1596 || errno == ECONNRESET || errno == ETIMEDOUT | |
1597 || errno == ECONNREFUSED), | |
1598 0, "%s(%s%s): %s", | |
1599 syscall_name, | |
1600 ofp_rem_str(ofp), | |
1601 fnm_lno(&fnm_buf, flod_path, ofp->lno), | |
1602 errno == EINVAL | |
1603 ? "likely connection refused or local firewall" | |
1604 : ERROR_STR()); | |
1605 | |
1606 /* do not back off connection attempts for SOCKS or NAT because | |
1607 * the peer cannot trigger anything by connecting to us */ | |
1608 oflod_backoff(ofp, (ofp->mp->flags & FLODMAP_FG_ACT) != 0); | |
1609 oflod_close(ofp, 1); | |
1610 return -1; | |
1611 } | |
1612 | |
1613 if (!oflod_connect_fin(ofp)) { | |
1614 oflod_close(ofp, 1); | |
1615 return -1; | |
1616 } | |
1617 | |
1618 return 1; | |
1619 } | |
1620 | |
1621 | |
1622 | |
1623 void | |
1624 oflod_open(OFLOD_INFO *ofp) | |
1625 { | |
1626 DCC_FNM_LNO_BUF fnm_buf; | |
1627 DCC_SOCKU loc_su, su2; | |
1628 const DCC_SOCKU *sup; | |
1629 const SRVR_SOC *sp; | |
1630 int error; | |
1631 | |
1632 if (ofp->soc >= 0 | |
1633 || ofp->rem_hostname[0] == '\0' | |
1634 || OFLOD_OPT_OFF_ROGUE(ofp) | |
1635 || flods_st != FLODS_ST_ON | |
1636 || (ofp->mp->flags & FLODMAP_FG_PASSIVE)) | |
1637 return; | |
1638 | |
1639 if (!DB_IS_TIME(ofp->mp->otimers.retry, ofp->mp->otimers.retry_secs)) | |
1640 return; | |
1641 | |
1642 if (!flod_names_resolve_start()) | |
1643 return; /* wait for name resolution */ | |
1644 | |
1645 if (ofp->mp->rem_su.sa.sa_family == AF_UNSPEC) { | |
1646 rpt_err(ofp, 0, 0, "peer name %s: '%s'%s", | |
1647 ofp->rem_hostname, | |
1648 DCC_HSTRERROR(ofp->mp->host_error), | |
1649 fnm_lno(&fnm_buf, flod_path, ofp->lno)); | |
1650 oflod_backoff(ofp, 0); | |
1651 oflod_close(ofp, 1); | |
1652 return; | |
1653 } | |
1654 if (!LITCMP(ofp->mp->oflod_err.msg, "peer name ")) | |
1655 ofp->mp->oflod_err.msg[0] = '\0'; | |
1656 | |
1657 ofp->rem_su = ofp->mp->rem_su; | |
1658 | |
1659 ofp->soc = socket(ofp->rem_su.sa.sa_family, SOCK_STREAM, 0); | |
1660 if (ofp->soc < 0) { | |
1661 rpt_err(ofp, 0, 0, "flood socket(%s): %s", | |
1662 ofp_rem_str(ofp), ERROR_STR()); | |
1663 oflod_close(ofp, 1); | |
1664 return; | |
1665 } | |
1666 ++oflods.open; | |
1667 | |
1668 if (!set_flod_socket(ofp, 0, ofp->soc, | |
1669 ofp->rem_hostname, &ofp->rem_su)) { | |
1670 oflod_close(ofp, 1); | |
1671 return; | |
1672 } | |
1673 | |
1674 memset(&loc_su, 0, sizeof(loc_su)); | |
1675 if (ofp->loc_hostname[0] != '\0' | |
1676 || ofp->loc_port != 0) { | |
1677 /* Resolve the local host name. | |
1678 * This should not take significant time because | |
1679 * the local hostnames should be locally known. That | |
1680 * implies that we don't need to use a separate thread. */ | |
1681 if (ofp->loc_hostname[0] != '\0') { | |
1682 dcc_host_lock(); | |
1683 if (!dcc_get_host(ofp->loc_hostname, | |
1684 ofp->rem_su.sa.sa_family == AF_INET | |
1685 ? 0 : 1, | |
1686 &error)) { | |
1687 dcc_error_msg("flood local name %s: %s%s", | |
1688 ofp->loc_hostname, | |
1689 DCC_HSTRERROR(error), | |
1690 fnm_lno(&fnm_buf, flod_path, | |
1691 ofp->lno)); | |
1692 } else { | |
1693 /* match local address family to remote */ | |
1694 sup = dcc_hostaddrs; | |
1695 for (;;) { | |
1696 if (sup->sa.sa_family | |
1697 == ofp->rem_su.sa.sa_family) { | |
1698 loc_su = *sup; | |
1699 break; | |
1700 } | |
1701 if (++sup >= dcc_hostaddrs_end) { | |
1702 dcc_error_msg("family matching %s" | |
1703 " not available for %s", | |
1704 ofp_rem_str(ofp), | |
1705 ofp->loc_hostname); | |
1706 ofp->loc_hostname[0] = '\0'; | |
1707 break; | |
1708 } | |
1709 } | |
1710 } | |
1711 dcc_host_unlock(); | |
1712 } | |
1713 } | |
1714 | |
1715 /* If there is a single "-a address" other than localhost | |
1716 * and of the right family, then default to it. | |
1717 * but only if we are not trying to get past a firewall */ | |
1718 if ((ofp->mp->flags & (FLODMAP_FG_SOCKS | FLODMAP_FG_NAT)) == 0 | |
1719 && loc_su.sa.sa_family == AF_UNSPEC) { | |
1720 for (sp = srvr_socs; sp; sp = sp->fwd) { | |
1721 if (dcc_ipv6sutoipv4(&su2, &sp->su) | |
1722 && su2.ipv4.sin_addr.s_addr == ntohl(0x7f000001)) | |
1723 continue; | |
1724 if (sp->su.sa.sa_family != ofp->rem_su.sa.sa_family) | |
1725 continue; | |
1726 if (loc_su.sa.sa_family != AF_UNSPEC) { | |
1727 /* more than one, so give up */ | |
1728 memset(&loc_su, 0, sizeof(loc_su)); | |
1729 break; | |
1730 } | |
1731 loc_su = sp->su; | |
1732 } | |
1733 } | |
1734 | |
1735 if (loc_su.sa.sa_family != AF_UNSPEC | |
1736 || ofp->loc_port != 0) { | |
1737 loc_su.sa.sa_family = ofp->rem_su.sa.sa_family; | |
1738 *DCC_SU_PORTP(&loc_su) = ofp->loc_port; | |
1739 if (0 > bind(ofp->soc, &loc_su.sa, DCC_SU_LEN(&loc_su))) | |
1740 dcc_error_msg("bind(flood %s%s): %s", | |
1741 dcc_su2str_err(&loc_su), | |
1742 fnm_lno(&fnm_buf, flod_path, ofp->lno), | |
1743 ERROR_STR()); | |
1744 } | |
1745 | |
1746 oflod_connect_start(ofp, "connect"); | |
1747 } | |
1748 | |
1749 | |
1750 | |
1751 void | |
1752 oflod_write(OFLOD_INFO *ofp) | |
1753 { | |
1754 int i; | |
1755 | |
1756 if (ofp->obuf_len == 0) { | |
1757 if (!(ofp->flags & OFLOD_FG_CONNECTED) | |
1758 && 0 >= oflod_connect_start(ofp, "connect2")) | |
1759 return; | |
1760 oflod_fill(ofp); | |
1761 if (ofp->obuf_len == 0) | |
1762 return; | |
1763 } | |
1764 | |
1765 if (ofp->o_opts.flags & FLOD_OPT_SOCKS) | |
1766 i = Rsend(ofp->soc, &ofp->obuf.b, ofp->obuf_len, 0); | |
1767 else | |
1768 i = send(ofp->soc, &ofp->obuf.b, ofp->obuf_len, 0); | |
1769 if (i > 0) { | |
1770 ofp->obuf_len -= i; | |
1771 if (ofp->obuf_len != 0) | |
1772 memmove(&ofp->obuf.b[0], &ofp->obuf.b[i], | |
1773 ofp->obuf_len); | |
1774 ofp->oflod_alive = db_time.tv_sec; | |
1775 | |
1776 /* fill buffer so that the main loop will | |
1777 * ask select() when we can send again */ | |
1778 oflod_fill(ofp); | |
1779 return; | |
1780 } | |
1781 | |
1782 /* we had an error or EOF */ | |
1783 if (i < 0) { | |
1784 /* oflod_write() is called only when select() has said that | |
1785 * we can send() and so we should never see the non-blocking | |
1786 * send() fail. | |
1787 * However, Solaris nevertheless sometimes says EAGAIN */ | |
1788 if (DCC_BLOCK_ERROR()) { | |
1789 ofp->flags |= OFLOD_FG_EAGAIN; | |
1790 TMSG2_FLOD(ofp, "pause after send(flood to %s): %s", | |
1791 ofp_rem_str(ofp), ERROR_STR()); | |
1792 return; | |
1793 } | |
1794 | |
1795 rpt_err(ofp, 0, 0, "send(flood to %s): %s", | |
1796 ofp_rem_str(ofp), ERROR_STR()); | |
1797 } else { | |
1798 rpt_err(ofp, 0, 0, "premature end of flood to %s", | |
1799 ofp_rem_str(ofp)); | |
1800 } | |
1801 oflod_read(ofp); /* get any last error message */ | |
1802 oflod_close(ofp, 1); | |
1803 } | |
1804 | |
1805 | |
1806 /* parse end of transmission message for familiar complaints | |
1807 * to adjust retry timer */ | |
1808 int /* 1=try again soon, 0=ok, -1=failure */ | |
1809 oflod_parse_eof(OFLOD_INFO *ofp, u_char in, | |
1810 const DCC_FLOD_END *end, int msg_len) | |
1811 { | |
1812 if (msg_len >= LITZ(DCC_FLOD_OK_STR) | |
1813 && !strncmp(end->msg, DCC_FLOD_OK_STR, | |
1814 LITZ(DCC_FLOD_OK_STR))) { | |
1815 return 0; /* success */ | |
1816 } | |
1817 | |
1818 if (msg_len >= LITZ(DCC_FLOD_BAD_AUTH_MSG) | |
1819 && !strncmp(end->msg, DCC_FLOD_BAD_AUTH_MSG, | |
1820 LITZ(DCC_FLOD_BAD_AUTH_MSG))) { | |
1821 /* try the second password if available | |
1822 * after the peer rejects the first */ | |
1823 if (in) { | |
1824 if ((ofp->flags & OFLOD_FG_HAVE_2PASSWD) | |
1825 && !(ofp->flags & OFLOD_FG_I_USED_2PASSWD)) { | |
1826 ofp->flags |= OFLOD_FG_I_USED_2PASSWD; | |
1827 ofp->mp->flags |= FLODMAP_FG_USE_2PASSWD; | |
1828 return 1; /* try again soon */ | |
1829 } | |
1830 } else { | |
1831 if ((ofp->flags & OFLOD_FG_HAVE_2PASSWD) | |
1832 && !(ofp->flags & OFLOD_FG_O_USED_2PASSWD)) { | |
1833 ofp->flags |= OFLOD_FG_O_USED_2PASSWD; | |
1834 ofp->mp->flags |= FLODMAP_FG_USE_2PASSWD; | |
1835 return 1; /* try again soon */ | |
1836 } | |
1837 } | |
1838 return -1; | |
1839 } | |
1840 | |
1841 if (msg_len > LITZ(DCC_FLOD_BAD_VER_MSG) | |
1842 && !strncmp(end->msg, DCC_FLOD_BAD_VER_MSG, | |
1843 LITZ(DCC_FLOD_BAD_VER_MSG))) { | |
1844 /* notice if this peer demands a version | |
1845 * other than what we have been trying */ | |
1846 if (ofp->oversion != ofp->mp->iversion) { | |
1847 ofp->oversion = ofp->mp->iversion; | |
1848 return 1; /* try again soon */ | |
1849 } | |
1850 return -1; | |
1851 } | |
1852 | |
1853 return -1; | |
1854 } | |
1855 | |
1856 | |
1857 | |
1858 /* see what the target has to say about the reports we have been sending */ | |
1859 void | |
1860 oflod_read(OFLOD_INFO *ofp) | |
1861 { | |
1862 int used, req_len, recv_len; | |
1863 DB_PTR pos; | |
1864 int fail; | |
1865 | |
1866 again:; | |
1867 req_len = sizeof(ofp->ibuf) - ofp->ibuf_len; | |
1868 if (ofp->o_opts.flags & FLOD_OPT_SOCKS) | |
1869 recv_len = Rrecv(ofp->soc, &ofp->ibuf.b[ofp->ibuf_len], | |
1870 req_len, 0); | |
1871 else | |
1872 recv_len = recv(ofp->soc, &ofp->ibuf.b[ofp->ibuf_len], | |
1873 req_len, 0); | |
1874 if (recv_len < 0) { | |
1875 if (!DCC_BLOCK_ERROR()) { | |
1876 rpt_err(ofp, 1, 0, "recv(outgoing flood %s): %s", | |
1877 ofp_rem_str(ofp), ERROR_STR()); | |
1878 oflod_close(ofp, 1); | |
1879 } | |
1880 return; | |
1881 } | |
1882 if (recv_len > 0) { | |
1883 /* the connection is alive and working */ | |
1884 if (!(ofp->flags & (OFLOD_FG_SHUTDOWN_REQ | OFLOD_FG_SHUTDOWN))) | |
1885 ofp->oflod_alive = db_time.tv_sec; | |
1886 ofp->flags &= ~OFLOD_FG_NEW; | |
1887 if (!(ofp->flags & (OFLOD_FG_SHUTDOWN_REQ | |
1888 | OFLOD_FG_SHUTDOWN))) | |
1889 ofp->oflod_alive = db_time.tv_sec; | |
1890 | |
1891 /* limit the backoff for incoming SOCKS connection attempts | |
1892 * while the outgoing connection is working */ | |
1893 DB_ADJ_TIMER(&ofp->mp->itimers.retry, | |
1894 &ofp->mp->itimers.retry_secs, | |
1895 FLOD_RETRY_SECS); | |
1896 } | |
1897 | |
1898 ofp->ibuf_len += recv_len; | |
1899 while (ofp->ibuf_len >= ISZ(ofp->ibuf.r.pos)) { | |
1900 used = sizeof(ofp->ibuf.r.pos); | |
1901 | |
1902 pos = flod_pos2db_ptr(ofp->ibuf.r.pos); | |
1903 switch ((DCC_FLOD_POS_OPS)pos) { | |
1904 case DCC_FLOD_POS_END: | |
1905 /* Wait for all of the final status message or | |
1906 * until the target closes the TCP connection. | |
1907 * Do not worry if the target stops without | |
1908 * asking nicely, since at worst we will | |
1909 * resend whatever was in the pipe next time. */ | |
1910 if (ofp->ibuf_len <= ISZ(ofp->ibuf.r.end) | |
1911 && recv_len != 0) | |
1912 goto again; | |
1913 /* shut down after trying to recognize | |
1914 * a complaint from the target */ | |
1915 fail = oflod_parse_eof(ofp, 0, | |
1916 &ofp->ibuf.r.end, | |
1917 ofp->ibuf_len - FLOD_END_OVHD); | |
1918 rpt_err(ofp, fail>=0, 0, | |
1919 "outgoing flood end 'status from %s \"%.*s\"'", | |
1920 ofp_rem_str(ofp), | |
1921 ofp->ibuf_len - FLOD_END_OVHD, | |
1922 ofp->ibuf.r.end.msg); | |
1923 if (fail < 0) | |
1924 oflod_backoff(ofp, 0); | |
1925 oflod_close(ofp, fail<0); | |
1926 return; | |
1927 | |
1928 case DCC_FLOD_POS_END_REQ: | |
1929 /* try to update our pointers and shutdown() */ | |
1930 start_shutdown(ofp); | |
1931 ofp->mp->otimers.retry_secs = FLOD_RETRY_SECS; | |
1932 ofp->mp->otimers.retry = (db_time.tv_sec | |
1933 + FLOD_RETRY_SECS); | |
1934 if (!(ofp->mp->flags & FLODMAP_FG_PASSIVE)) | |
1935 TMSG2_FLOD(ofp, "postpone restarting flood to" | |
1936 " %s for %d" | |
1937 " seconds after end request", | |
1938 ofp_rem_str(ofp), FLOD_RETRY_SECS); | |
1939 break; | |
1940 | |
1941 case DCC_FLOD_POS_NOTE: | |
1942 /* wait until we get the length of the complaint */ | |
1943 if (ofp->ibuf_len < FLOD_NOTE_OVHD) | |
1944 goto again; | |
1945 used = ofp->ibuf.r.note.len; | |
1946 if (used > ISZ(ofp->ibuf.r.note) | |
1947 || used <= FLOD_NOTE_OVHD) { | |
1948 rpt_err(ofp, 0,0, | |
1949 "bogus outgoing flood note length" | |
1950 " %d from %s", | |
1951 used, ofp_rem_str(ofp)); | |
1952 oflod_close(ofp, 1); | |
1953 return; | |
1954 } | |
1955 if (ofp->ibuf_len < used) | |
1956 goto again; | |
1957 TMSG3_FLOD(ofp, "outgoing flood note from %s: \"%.*s\"", | |
1958 ofp_rem_str(ofp), | |
1959 used-FLOD_NOTE_OVHD, ofp->ibuf.r.note.str); | |
1960 break; | |
1961 | |
1962 case DCC_FLOD_POS_COMPLAINT: | |
1963 /* wait until we get the length of the complaint */ | |
1964 if (ofp->ibuf_len < FLOD_NOTE_OVHD) | |
1965 goto again; | |
1966 used = ofp->ibuf.r.note.len; | |
1967 if (used > ISZ(ofp->ibuf.r.note) | |
1968 || used <= FLOD_NOTE_OVHD) { | |
1969 rpt_err(ofp, 0, 0, | |
1970 "bogus outgoing flood complaint length" | |
1971 " %d from %s", | |
1972 used, ofp_rem_str(ofp)); | |
1973 oflod_close(ofp, 1); | |
1974 return; | |
1975 } | |
1976 if (ofp->ibuf_len < used) | |
1977 goto again; | |
1978 if (CK_FLOD_CNTERR(&ofp->lc.complaint)) | |
1979 flod_cnterr(&ofp->lc.complaint, | |
1980 "outgoing flood complaint from %s:" | |
1981 " %.*s", | |
1982 ofp_rem_str(ofp), | |
1983 used - FLOD_NOTE_OVHD, | |
1984 ofp->ibuf.r.note.str); | |
1985 break; | |
1986 | |
1987 case DCC_FLOD_POS_REWIND: | |
1988 dcc_trace_msg("flood rewind request from %s", | |
1989 ofp_rem_str(ofp)); | |
1990 ofp->mp->flags |= FLODMAP_FG_REWINDING; | |
1991 ofp->cur_pos = ofp->mp->confirm_pos = DB_PTR_BASE; | |
1992 ofp->recv_pos = ofp->xmit_pos = DB_PTR_BASE; | |
1993 ofp->rewind_pos = db_csize; | |
1994 get_oflods_max_cur_pos(); | |
1995 oflod_fill(ofp); | |
1996 break; | |
1997 | |
1998 case DCC_FLOD_POS_FFWD_IN: | |
1999 dcc_trace_msg("FFWD its input from %s", | |
2000 ofp_rem_str(ofp)); | |
2001 ofp->cur_pos = db_csize; | |
2002 get_oflods_max_cur_pos(); | |
2003 break; | |
2004 | |
2005 | |
2006 default: | |
2007 /* The position from the peer must be one we sent, | |
2008 * and in the window we expect unless our | |
2009 * window has been broken by rewinding. | |
2010 * Even if our window is broken, the position must | |
2011 * be reasonable. */ | |
2012 if ((pos < ofp->recv_pos | |
2013 || pos > ofp->xmit_pos) | |
2014 && (!(ofp->mp->flags & FLODMAP_FG_REWINDING) | |
2015 || pos < DCC_FLOD_POS_MIN | |
2016 || pos > db_csize)) { | |
2017 rpt_err(ofp, 0, 0, | |
2018 "bogus confirmed flood position" | |
2019 " "L_HPAT" from %s;" | |
2020 " recv_pos="L_HPAT" xmit_pos="L_HPAT, | |
2021 pos, ofp_rem_str(ofp), | |
2022 ofp->recv_pos, ofp->xmit_pos); | |
2023 oflod_close(ofp, 1); | |
2024 return; | |
2025 } | |
2026 ofp->recv_pos = pos; | |
2027 if (ofp->xmit_pos == ofp->recv_pos) | |
2028 ofp->mp->confirm_pos = ofp->cur_pos; | |
2029 else if (ofp->mp->confirm_pos < ofp->recv_pos) | |
2030 ofp->mp->confirm_pos = ofp->recv_pos; | |
2031 | |
2032 /* things are going ok, so reset the connect() backoff | |
2033 * and the no-connection complaint */ | |
2034 ofp->mp->otimers.retry_secs = 0; | |
2035 ofp->mp->otimers.msg_secs = FLOD_IN_COMPLAIN1; | |
2036 ofp->mp->otimers.msg = (db_time.tv_sec | |
2037 + FLOD_IN_COMPLAIN1); | |
2038 break; | |
2039 } | |
2040 | |
2041 ofp->ibuf_len -= used; | |
2042 if (ofp->ibuf_len == 0) | |
2043 return; | |
2044 if (ofp->ibuf_len < 0) | |
2045 dcc_logbad(EX_SOFTWARE, "ofp->ibuf_len=%d", | |
2046 ofp->ibuf_len); | |
2047 /* assume there will rarely be more than one position | |
2048 * in the buffer */ | |
2049 memmove(ofp->ibuf.b, &ofp->ibuf.b[used], ofp->ibuf_len); | |
2050 } | |
2051 | |
2052 if (recv_len == 0) { | |
2053 /* before closing, the peer is supposed to send a | |
2054 * "position" of DCC_FLOD_POS_END followed by | |
2055 * an ASCII message */ | |
2056 if (ofp->ibuf_len != 0) | |
2057 rpt_err(ofp, 0, 0, | |
2058 "truncated outgoing flood response from %s", | |
2059 ofp_rem_str(ofp)); | |
2060 else | |
2061 rpt_err(ofp, 0, 0, | |
2062 "missing outgoing flood response from %s", | |
2063 ofp_rem_str(ofp)); | |
2064 oflod_close(ofp, 1); | |
2065 } | |
2066 } | |
2067 | |
2068 | |
2069 | |
2070 static void | |
2071 oflods_ck(void) | |
2072 { | |
2073 OFLOD_INFO *ofp; | |
2074 | |
2075 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) { | |
2076 if (ofp->rem_hostname[0] == '\0') | |
2077 break; | |
2078 | |
2079 if (ofp->flags & OFLOD_FG_EAGAIN) { | |
2080 TMSG1_FLOD(ofp, "resume flooding %s after EAGAIN", | |
2081 ofp->rem_hostname); | |
2082 ofp->flags &= ~OFLOD_FG_EAGAIN; | |
2083 } | |
2084 | |
2085 if (!(ofp->flags & OFLOD_FG_CONNECTED)) | |
2086 continue; | |
2087 | |
2088 /* close the peer has failed to respond to a shutdown request */ | |
2089 if (ofp->flags & (OFLOD_FG_SHUTDOWN_REQ | OFLOD_FG_SHUTDOWN)) { | |
2090 if (stopint && OFP_DEAD(ofp, SHUTDOWN_DELAY)) { | |
2091 rpt_err(ofp, 1, 0, | |
2092 "stopping; force close flood to %s", | |
2093 ofp_rem_str(ofp)); | |
2094 oflod_close(ofp, 0); | |
2095 | |
2096 } else if (OFP_DEAD(ofp, KEEPALIVE_OUT_STOP)) { | |
2097 rpt_err(ofp, 1, 0, | |
2098 "off; force close flood to %s", | |
2099 ofp_rem_str(ofp)); | |
2100 oflod_close(ofp, 0); | |
2101 } | |
2102 continue; | |
2103 } | |
2104 | |
2105 /* Shut down any streams that have been quiet for too long. | |
2106 * If the TCP connection is healthy we should at least have | |
2107 * received keep alive position repetitions or "are you there?" | |
2108 * notes from the peer. */ | |
2109 if (OFP_DEAD(ofp, KEEPALIVE_OUT)) { | |
2110 rpt_err(ofp, 1, 0, | |
2111 "keepalive start shutdown flood to %s", | |
2112 ofp_rem_str(ofp)); | |
2113 start_shutdown(ofp); | |
2114 continue; | |
2115 } | |
2116 } | |
2117 } | |
2118 | |
2119 | |
2120 | |
2121 static void | |
2122 oflods_stop(u_char force) | |
2123 { | |
2124 OFLOD_INFO *ofp; | |
2125 | |
2126 if (!flod_mmaps) | |
2127 return; | |
2128 | |
2129 for (ofp = oflods.infos; ofp <= LAST(oflods.infos); ++ofp) { | |
2130 if (ofp->rem_hostname[0] == '\0') | |
2131 break; | |
2132 if (ofp->soc < 0) | |
2133 continue; | |
2134 if (force || !(ofp->flags & OFLOD_FG_CONNECTED)) { | |
2135 rpt_err(ofp, 1, 0, "halting flood to %s", | |
2136 ofp_rem_str(ofp)); | |
2137 oflod_close(ofp, 0); | |
2138 } else if (!(ofp->flags & (OFLOD_FG_SHUTDOWN_REQ | |
2139 | OFLOD_FG_SHUTDOWN))) { | |
2140 rpt_err(ofp, 1, 0, "stopping flood to %s", | |
2141 ofp_rem_str(ofp)); | |
2142 start_shutdown(ofp); | |
2143 } | |
2144 } | |
2145 | |
2146 if (oflods.open == 0 && iflods.open == 0) | |
2147 oflods_clear(); | |
2148 } | |
2149 | |
2150 | |
2151 | |
2152 void | |
2153 flods_stop(const char *iflod_msg, u_char force) | |
2154 { | |
2155 flods_st = FLODS_ST_OFF; | |
2156 iflods_stop(iflod_msg, force); | |
2157 oflods_stop(force); | |
2158 } | |
2159 | |
2160 | |
2161 | |
2162 /* (re)start listening for incoming floods and sending outgoing floods */ | |
2163 void | |
2164 flods_restart(const char *msg, u_char force_ck) | |
2165 { | |
2166 if (FLODS_OK()) | |
2167 flods_st = FLODS_ST_RESTART; | |
2168 iflods_stop(msg, 0); | |
2169 flods_ck(force_ck); | |
2170 } | |
2171 | |
2172 | |
2173 | |
2174 /* load the ids file if it has changed */ | |
2175 int /* -1=our ID missing, 0=sick file */ | |
2176 check_load_ids(u_char mode) /* 0=if needed, 1=reboot, 2=new db */ | |
2177 { | |
2178 const ID_TBL *tp; | |
2179 int result; | |
2180 | |
2181 result = load_ids(dcc_emsg, my_srvr_id, &tp, mode ? 1 : 0 ); | |
2182 if (result == 2) | |
2183 return 1; | |
2184 if (result <= 0) | |
2185 return result; | |
2186 | |
2187 if (mode == 0 || ( mode == 2 && db_debug)) | |
2188 dcc_trace_msg("reloaded %s", ids_path); | |
2189 | |
2190 if (mode == 0) { | |
2191 if (flod_mtime > 1) | |
2192 flod_mtime = 1; | |
2193 flods_restart("restart flooding with new IDs", 0); | |
2194 } | |
2195 | |
2196 return 1; | |
2197 } | |
2198 | |
2199 | |
2200 /* called periodically and at need */ | |
2201 void | |
2202 flods_ck(u_char force) | |
2203 { | |
2204 static int map_delayed; | |
2205 IFLOD_INFO *ifp; | |
2206 OFLOD_INFO *ofp; | |
2207 struct stat flod_sb; | |
2208 struct timeval; | |
2209 DCC_TS past, present; | |
2210 int rcd_len; | |
2211 int work; | |
2212 u_char loaded; /* mapped flod.map file just for this */ | |
2213 | |
2214 if (force) /* force hostname resolution */ | |
2215 got_hosts = 0; | |
2216 | |
2217 for (ifp = iflods.infos; ifp <= LAST(iflods.infos); ++ifp) { | |
2218 if (ifp->soc < 0) | |
2219 continue; | |
2220 | |
2221 /* end incoming connections that are not completed in time */ | |
2222 ofp = ifp->ofp; | |
2223 if (!ofp) { | |
2224 iflod_read(ifp); | |
2225 if (ifp->soc < 0) | |
2226 continue; | |
2227 ofp = ifp->ofp; | |
2228 if (!ofp) { | |
2229 if (IFP_DEAD(ifp, KEEPALIVE_IN_STOP)) | |
2230 iflod_close(ifp, 1, 1, 0, | |
2231 "no authentication from %s", | |
2232 ifp_rem_str(ifp)); | |
2233 continue; | |
2234 } | |
2235 } | |
2236 | |
2237 /* allow more complaints */ | |
2238 if (DB_IS_TIME(ofp->limit_reset, FLOD_LIM_CLEAR_SECS) | |
2239 || force) { | |
2240 FLOD_LIMCNT *lc; | |
2241 | |
2242 complained_many_iflods = 0; | |
2243 for (lc = (FLOD_LIMCNT *)&ofp->lc; | |
2244 lc < (FLOD_LIMCNT *)(sizeof(ofp->lc) | |
2245 +(char *)&ofp->lc); | |
2246 ++lc) { | |
2247 lc->lim = lc->cur; | |
2248 } | |
2249 ofp->limit_reset = db_time.tv_sec+FLOD_LIM_CLEAR_SECS; | |
2250 } | |
2251 | |
2252 if (!(ifp->flags & IFLOD_FG_VERS_CK)) | |
2253 continue; /* done if peer not really known */ | |
2254 | |
2255 save_flod_cnts(ofp); | |
2256 | |
2257 if (!IFP_DEAD(ifp, KEEPALIVE_IN)) { | |
2258 /* The link is warm. | |
2259 * Send a delayed position update if needed. */ | |
2260 iflod_send_pos(ifp, 0); | |
2261 | |
2262 } else if (ifp->flags & IFLOD_FG_END_REQ) { | |
2263 /* The link is cold. If we have asked the peer to | |
2264 * stop but it has not, then break the link. */ | |
2265 iflod_close(ifp, 1, 0, 0, "%s ignored close request", | |
2266 ifp_rem_str(ifp)); | |
2267 | |
2268 } else { | |
2269 /* The link is cold., so repeat our position or | |
2270 * send a note as a keepalive. The will be closed if | |
2271 * that fails. */ | |
2272 iflod_send_pos(ifp, 1); | |
2273 } | |
2274 } | |
2275 | |
2276 if (FLODS_OK()) { | |
2277 /* stop and restart the pumps if the list of peers has | |
2278 * changed or if our map has disappeared | |
2279 * and if dbclean is not running */ | |
2280 if (0 > stat(flod_path, &flod_sb)) { | |
2281 if (errno != ENOENT | |
2282 && flod_mtime != 0) | |
2283 dcc_error_msg("stat(%s): %s", | |
2284 flod_path, ERROR_STR()); | |
2285 flod_sb.st_mtime = 0; | |
2286 } | |
2287 if (flod_mtime != 0 | |
2288 && 0 > access(flod_mmap_path, W_OK | R_OK)) { | |
2289 if (errno != ENOENT) | |
2290 dcc_error_msg("access(%s): %s", | |
2291 flod_mmap_path, ERROR_STR()); | |
2292 flod_sb.st_mtime = 0; | |
2293 } | |
2294 if (flods_st != FLODS_ST_RESTART | |
2295 && flod_sb.st_mtime != flod_mtime) { | |
2296 if (flod_mtime > 1) { | |
2297 dcc_trace_msg("%s has changed", flod_path); | |
2298 flod_mtime = 0; | |
2299 } | |
2300 flods_st = FLODS_ST_RESTART; | |
2301 } | |
2302 } | |
2303 | |
2304 if (flods_st != FLODS_ST_ON) { | |
2305 flods_stop("", 0); | |
2306 | |
2307 /* wait until the previous floods have stopped and dbclean | |
2308 * is not running to restart flooding */ | |
2309 if (FLODS_OK()) { | |
2310 if (oflods.open != 0 || iflods.open != 0 | |
2311 || !flod_names_resolve_ck()) { | |
2312 flods_st = FLODS_ST_RESTART; | |
2313 /* check again soon but not immediately */ | |
2314 RUSH_NEXT_FLODS_CK(); | |
2315 } else { | |
2316 if (load_flod(1)) | |
2317 flods_st = FLODS_ST_ON; | |
2318 } | |
2319 } | |
2320 } | |
2321 | |
2322 /* try to reap the hostname resolving child */ | |
2323 flod_names_resolve_ck(); | |
2324 | |
2325 /* that is all we can do if flooding is off or dbclean is running */ | |
2326 if (!FLODS_OK_ON()) { | |
2327 oflods_ck(); | |
2328 return; | |
2329 } | |
2330 | |
2331 iflods_listen(); | |
2332 | |
2333 /* generate summaries of some of our delayed reports */ | |
2334 dcc_timeval2ts(&past, &db_time, -summarize_delay_secs); | |
2335 dcc_timeval2ts(&present, &db_time, 0); | |
2336 if (flod_mmaps) { | |
2337 if (flod_mmaps->delay_pos > db_csize | |
2338 || flod_mmaps->delay_pos < DB_PTR_BASE) | |
2339 flod_mmaps->delay_pos = DB_PTR_BASE; | |
2340 work = 0; | |
2341 while (flod_mmaps->delay_pos < db_csize) { | |
2342 if (!db_map_rcd(0, &db_sts.sumrcd, | |
2343 flod_mmaps->delay_pos, | |
2344 &rcd_len)) { | |
2345 flod_mmaps->delay_pos = db_csize; | |
2346 break; | |
2347 } | |
2348 /* only our own reports are delayed */ | |
2349 if (DB_RCD_DELAY(db_sts.sumrcd.d.r)) { | |
2350 /* wait until it is time */ | |
2351 if (dcc_ts_newer_ts(&db_sts.sumrcd.d.r->ts, | |
2352 &past) | |
2353 && !dcc_ts_newer_ts(&db_sts.sumrcd.d.r->ts, | |
2354 &present)) | |
2355 break; | |
2356 if (!summarize_dly()) { | |
2357 flod_mmaps->delay_pos = db_csize; | |
2358 break; | |
2359 } | |
2360 } | |
2361 flod_mmaps->delay_pos += rcd_len; | |
2362 | |
2363 if (++work >= 1000) { | |
2364 /* spend at most 0.5 second at this | |
2365 * and then let other processes run*/ | |
2366 gettimeofday(&db_time, 0); | |
2367 if (tv_diff2us(&db_time, &wake_time)>DCC_US/2) { | |
2368 next_flods_ck = 0; | |
2369 break; | |
2370 } | |
2371 work = 0; | |
2372 } | |
2373 } | |
2374 | |
2375 /* prime the outgoing pumps */ | |
2376 for (ofp = oflods.infos; | |
2377 ofp <= LAST(oflods.infos); | |
2378 ++ofp) { | |
2379 if (ofp->rem_hostname[0] == '\0') | |
2380 break; | |
2381 | |
2382 if (ofp->soc >= 0) { | |
2383 /* The connection is no longer new if it has | |
2384 * been a while since it was completed */ | |
2385 if ((ofp->flags & OFLOD_FG_NEW) | |
2386 && DB_IS_TIME(ofp->mp->cnts.out_conn_changed | |
2387 + FLODS_CK_SECS, | |
2388 FLODS_CK_SECS)) | |
2389 ofp->flags &= ~OFLOD_FG_NEW; | |
2390 oflod_fill(ofp); | |
2391 } else { | |
2392 oflod_open(ofp); | |
2393 } | |
2394 | |
2395 iflod_socks_start(ofp); | |
2396 } | |
2397 } | |
2398 | |
2399 /* complain once per day about incoming links that are not working | |
2400 * even if dbclean is continually running. */ | |
2401 loaded = 0; | |
2402 if (flod_mmaps) { | |
2403 map_delayed = 0; | |
2404 } else if ((force || ++map_delayed > 10) && load_flod(0)) { | |
2405 loaded = 1; | |
2406 map_delayed = 0; | |
2407 } | |
2408 for (ofp = oflods.infos; | |
2409 ofp->rem_hostname[0] != '\0' && ofp <= LAST(oflods.infos) | |
2410 && flod_mmaps; | |
2411 ++ofp) { | |
2412 FLOD_MMAP *mp; | |
2413 LAST_ERROR *ep; | |
2414 const char *msg; | |
2415 | |
2416 if (force) { | |
2417 /* Force new outgoing connection attempts. Also force | |
2418 * incoming error messages soon but not now to give new | |
2419 * connetions a chance to be triggered by outgoing | |
2420 * connections. */ | |
2421 flod_try_again(ofp); | |
2422 } | |
2423 | |
2424 mp = ofp->mp; | |
2425 if (ofp->soc < 0 | |
2426 && (ofp->mp->flags & FLODMAP_FG_PASSIVE) | |
2427 && !OFLOD_OPT_OFF_ROGUE(ofp) | |
2428 && DB_IS_TIME(mp->otimers.msg, mp->otimers.msg_secs)) { | |
2429 ep = &mp->oflod_err; | |
2430 msg = (ep->complained | |
2431 ? "" | |
2432 : ep->msg[0] != '\0' | |
2433 ? ep->msg | |
2434 : ep->trace_msg); | |
2435 dcc_error_msg("no passive connection to %s%s%s%s", | |
2436 ofp->rem_hostname, | |
2437 msg[0] ? ": \"" : "", | |
2438 msg, | |
2439 msg[0] ? "\"" : ""); | |
2440 ep->complained = 1; | |
2441 mp->otimers.msg_secs = FLOD_IN_COMPLAIN; | |
2442 mp->otimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN; | |
2443 } | |
2444 | |
2445 if ((ofp->mp->flags & (FLODMAP_FG_SOCKS | FLODMAP_FG_NAT)) == 0 | |
2446 && !ofp->ifp | |
2447 && !IFLOD_OPT_OFF_ROGUE(ofp) | |
2448 && DB_IS_TIME(mp->itimers.msg, mp->itimers.msg_secs)) { | |
2449 ep = &mp->iflod_err; | |
2450 msg = (ep->complained | |
2451 ? "" | |
2452 : ep->msg[0] != '\0' | |
2453 ? ep->msg | |
2454 : ep->trace_msg); | |
2455 dcc_error_msg("no incoming connection from %s%s%s%s", | |
2456 ofp->rem_hostname, | |
2457 msg[0] ? ": \"" : "", | |
2458 msg, | |
2459 msg[0] ? "\"" : ""); | |
2460 ep->complained = 1; | |
2461 mp->itimers.msg_secs = FLOD_IN_COMPLAIN; | |
2462 mp->itimers.msg = db_time.tv_sec + FLOD_IN_COMPLAIN; | |
2463 } | |
2464 } | |
2465 if (loaded) | |
2466 oflods_clear(); | |
2467 | |
2468 oflods_ck(); | |
2469 } | |
2470 | |
2471 | |
2472 | |
2473 void | |
2474 flods_init(void) | |
2475 { | |
2476 IFLOD_INFO *ifp; | |
2477 | |
2478 for (ifp = iflods.infos; ifp <= LAST(iflods.infos); ++ifp) | |
2479 ifp->soc = -1; | |
2480 oflods_clear(); | |
2481 | |
2482 flods_restart("", 1); | |
2483 } |