0
|
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 } |