/[cvs]/eggdrop1.8/src/botnet.c
ViewVC logotype

Contents of /eggdrop1.8/src/botnet.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Thu Aug 5 18:12:05 2010 UTC (8 years, 9 months ago) by pseudo
Branch: MAIN
Changes since 1.1: +37 -15 lines
File MIME type: text/x-chdr
Added new, full IPv6 support to eggdrop.

1 /*
2 * botnet.c -- handles:
3 * keeping track of which bot's connected where in the chain
4 * dumping a list of bots or a bot tree to a user
5 * channel name associations on the party line
6 * rejecting a bot
7 * linking, unlinking, and relaying to another bot
8 * pinging the bots periodically and checking leaf status
9 *
10 * $Id: botnet.c,v 1.1.1.1 2010/07/26 21:11:06 simple Exp $
11 */
12 /*
13 * Copyright (C) 1997 Robey Pointer
14 * Copyright (C) 1999 - 2010 Eggheads Development Team
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 */
30
31 #include "main.h"
32 #include "tandem.h"
33
34 extern int dcc_total, backgrd, connect_timeout, max_dcc, egg_numver;
35 extern struct userrec *userlist;
36 extern struct dcc_t *dcc;
37 extern time_t now;
38 extern Tcl_Interp *interp;
39
40 tand_t *tandbot; /* Keep track of tandem bots on the botnet */
41 party_t *party; /* Keep track of people on the botnet */
42 static int maxparty = 50; /* Maximum space for party line members */
43 int tands = 0; /* Number of bots on the botnet */
44 int parties = 0; /* Number of people on the botnet */
45 char botnetnick[HANDLEN + 1] = ""; /* Botnet nickname */
46 int share_unlinks = 0; /* Allow remote unlinks of my sharebots? */
47
48
49 int expmem_botnet()
50 {
51 int size = 0, i;
52 tand_t *bot;
53
54 for (bot = tandbot; bot; bot = bot->next)
55 size += sizeof(tand_t);
56 size += (maxparty * sizeof(party_t));
57 for (i = 0; i < parties; i++) {
58 if (party[i].away)
59 size += strlen(party[i].away) + 1;
60 if (party[i].from)
61 size += strlen(party[i].from) + 1;
62 }
63 return size;
64 }
65
66 void init_bots()
67 {
68 tandbot = NULL;
69 /* Grab space for 50 bots for now -- expand later as needed */
70 maxparty = 50;
71 party = nmalloc(maxparty * sizeof(*party));
72 }
73
74 tand_t *findbot(char *who)
75 {
76 tand_t *ptr;
77
78 for (ptr = tandbot; ptr; ptr = ptr->next)
79 if (!egg_strcasecmp(ptr->bot, who))
80 return ptr;
81 return NULL;
82 }
83
84 /* Add a tandem bot to our chain list
85 */
86 void addbot(char *who, char *from, char *next, char flag, int vernum)
87 {
88 tand_t **ptr = &tandbot, *ptr2;
89
90 while (*ptr) {
91 if (!egg_strcasecmp((*ptr)->bot, who))
92 putlog(LOG_BOTS, "*", "!!! Duplicate botnet bot entry!!");
93 ptr = &((*ptr)->next);
94 }
95 ptr2 = nmalloc(sizeof(tand_t));
96 strncpy(ptr2->bot, who, HANDLEN);
97 ptr2->bot[HANDLEN] = 0;
98 ptr2->share = flag;
99 ptr2->ver = vernum;
100 ptr2->next = *ptr;
101 *ptr = ptr2;
102 /* May be via itself */
103 ptr2->via = findbot(from);
104 if (!egg_strcasecmp(next, botnetnick))
105 ptr2->uplink = (tand_t *) 1;
106 else
107 ptr2->uplink = findbot(next);
108 tands++;
109 }
110
111 void updatebot(int idx, char *who, char share, int vernum)
112 {
113 tand_t *ptr = findbot(who);
114
115 if (ptr) {
116 if (share)
117 ptr->share = share;
118 if (vernum)
119 ptr->ver = vernum;
120 botnet_send_update(idx, ptr);
121 }
122 }
123
124 /* For backward 1.0 compatibility:
125 * grab the (first) sock# for a user on another bot
126 */
127 int partysock(char *bot, char *nick)
128 {
129 int i;
130
131 for (i = 0; i < parties; i++) {
132 if ((!egg_strcasecmp(party[i].bot, bot)) &&
133 (!egg_strcasecmp(party[i].nick, nick)))
134 return party[i].sock;
135 }
136 return 0;
137 }
138
139 /* New botnet member
140 */
141 int addparty(char *bot, char *nick, int chan, char flag, int sock,
142 char *from, int *idx)
143 {
144 int i;
145
146 for (i = 0; i < parties; i++) {
147 /* Just changing the channel of someone already on? */
148 if (!egg_strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
149 int oldchan = party[i].chan;
150
151 party[i].chan = chan;
152 party[i].timer = now;
153 if (from[0]) {
154 if (flag == ' ')
155 flag = '-';
156 party[i].flag = flag;
157 if (party[i].from)
158 nfree(party[i].from);
159 party[i].from = nmalloc(strlen(from) + 1);
160 strcpy(party[i].from, from);
161 }
162 *idx = i;
163 return oldchan;
164 }
165 }
166 /* New member */
167 if (parties == maxparty) {
168 maxparty += 50;
169 party = (party_t *) nrealloc((void *) party, maxparty * sizeof(party_t));
170 }
171 strncpy(party[parties].nick, nick, HANDLEN);
172 party[parties].nick[HANDLEN] = 0;
173 strncpy(party[parties].bot, bot, HANDLEN);
174 party[parties].bot[HANDLEN] = 0;
175 party[parties].chan = chan;
176 party[parties].sock = sock;
177 party[parties].status = 0;
178 party[parties].away = 0;
179 party[parties].timer = now; /* cope. */
180 if (from[0]) {
181 if (flag == ' ')
182 flag = '-';
183 party[parties].flag = flag;
184 party[parties].from = nmalloc(strlen(from) + 1);
185 strcpy(party[parties].from, from);
186 } else {
187 party[parties].flag = ' ';
188 party[parties].from = nmalloc(10);
189 strcpy(party[parties].from, "(unknown)");
190 }
191 *idx = parties;
192 parties++;
193 return -1;
194 }
195
196 /* Alter status flags for remote party-line user.
197 */
198 void partystat(char *bot, int sock, int add, int rem)
199 {
200 int i;
201
202 for (i = 0; i < parties; i++) {
203 if ((!egg_strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
204 party[i].status |= add;
205 party[i].status &= ~rem;
206 }
207 }
208 }
209
210 /* Other bot is sharing idle info.
211 */
212 void partysetidle(char *bot, int sock, int secs)
213 {
214 int i;
215
216 for (i = 0; i < parties; i++) {
217 if ((!egg_strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
218 party[i].timer = (now - (time_t) secs);
219 }
220 }
221 }
222
223 /* Return someone's chat channel.
224 */
225 int getparty(char *bot, int sock)
226 {
227 int i;
228
229 for (i = 0; i < parties; i++) {
230 if (!egg_strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
231 return i;
232 }
233 }
234 return -1;
235 }
236
237 /* Un-idle someone
238 */
239 int partyidle(char *bot, char *nick)
240 {
241 int i, ok = 0;
242
243 for (i = 0; i < parties; i++) {
244 if ((!egg_strcasecmp(party[i].bot, bot)) &&
245 (!egg_strcasecmp(party[i].nick, nick))) {
246 party[i].timer = now;
247 ok = 1;
248 }
249 }
250 return ok;
251 }
252
253 /* Change someone's nick
254 */
255 int partynick(char *bot, int sock, char *nick)
256 {
257 char work[HANDLEN + 1];
258 int i;
259
260 for (i = 0; i < parties; i++) {
261 if (!egg_strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
262 strcpy(work, party[i].nick);
263 strncpy(party[i].nick, nick, HANDLEN);
264 party[i].nick[HANDLEN] = 0;
265 strcpy(nick, work);
266 return i;
267 }
268 }
269 return -1;
270 }
271
272 /* Set away message
273 */
274 void partyaway(char *bot, int sock, char *msg)
275 {
276 int i;
277
278 for (i = 0; i < parties; i++) {
279 if ((!egg_strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
280 if (party[i].away)
281 nfree(party[i].away);
282 if (msg[0]) {
283 party[i].away = nmalloc(strlen(msg) + 1);
284 strcpy(party[i].away, msg);
285 } else
286 party[i].away = 0;
287 }
288 }
289 }
290
291 /* Remove a tandem bot from the chain list. */
292 void rembot(char *whoin)
293 {
294 tand_t **ptr = &tandbot, *ptr2;
295 struct userrec *u;
296 char *who = NULL;
297 size_t len = 0;
298
299 /* Need to save the nick for later as it MAY be a pointer to ptr->bot, and we free(ptr) in here. */
300 len = strlen(whoin);
301 who = nmalloc(len + 1);
302 strncpyz(who, whoin, len + 1);
303
304 while (*ptr) {
305 if (!egg_strcasecmp((*ptr)->bot, who))
306 break;
307 ptr = &((*ptr)->next);
308 }
309 if (!*ptr) {
310 /* May have just .unlink *'d. */
311 nfree(who);
312 return;
313 }
314 check_tcl_disc(who);
315
316 u = get_user_by_handle(userlist, who);
317 if (u != NULL)
318 touch_laston(u, "unlinked", now);
319
320 ptr2 = *ptr;
321 *ptr = ptr2->next;
322 nfree(ptr2);
323 tands--;
324
325 dupwait_notify(who);
326 nfree(who);
327 }
328
329 void remparty(char *bot, int sock)
330 {
331 int i;
332
333 for (i = 0; i < parties; i++)
334 if ((!egg_strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
335 parties--;
336 if (party[i].from)
337 nfree(party[i].from);
338 if (party[i].away)
339 nfree(party[i].away);
340 if (i < parties) {
341 strcpy(party[i].bot, party[parties].bot);
342 strcpy(party[i].nick, party[parties].nick);
343 party[i].chan = party[parties].chan;
344 party[i].sock = party[parties].sock;
345 party[i].flag = party[parties].flag;
346 party[i].status = party[parties].status;
347 party[i].timer = party[parties].timer;
348 party[i].from = party[parties].from;
349 party[i].away = party[parties].away;
350 }
351 }
352 }
353
354 /* Cancel every user that was on a certain bot
355 */
356 void rempartybot(char *bot)
357 {
358 int i;
359
360 for (i = 0; i < parties; i++)
361 if (!egg_strcasecmp(party[i].bot, bot)) {
362 if (party[i].chan >= 0)
363 check_tcl_chpt(bot, party[i].nick, party[i].sock, party[i].chan);
364 remparty(bot, party[i].sock);
365 i--;
366 }
367 }
368
369 /* Remove every bot linked 'via' bot <x>
370 */
371 void unvia(int idx, tand_t *who)
372 {
373 tand_t *bot, *bot2;
374
375 if (!who)
376 return; /* Safety */
377 rempartybot(who->bot);
378 bot = tandbot;
379 while (bot) {
380 if (bot->uplink == who) {
381 unvia(idx, bot);
382 bot2 = bot->next;
383 rembot(bot->bot);
384 bot = bot2;
385 } else
386 bot = bot->next;
387 }
388 #ifndef NO_OLD_BOTNET
389 /* Every bot unvia's bots behind anyway, so why send msg's for
390 * EVERY one? - will this break things?!
391 */
392 tandout_but(idx, "unlinked %s\n", who->bot);
393 #endif
394 }
395
396 /* Return index into dcc list of the bot that connects us to bot <x>
397 */
398 int nextbot(char *who)
399 {
400 int j;
401 tand_t *bot = findbot(who);
402
403 if (!bot)
404 return -1;
405
406 for (j = 0; j < dcc_total; j++)
407 if (bot->via && !egg_strcasecmp(bot->via->bot, dcc[j].nick) &&
408 (dcc[j].type == &DCC_BOT))
409 return j;
410 return -1; /* We're not connected to 'via' */
411 }
412
413 /* Return name of the bot that is directly connected to bot X
414 */
415 char *lastbot(char *who)
416 {
417 tand_t *bot = findbot(who);
418
419 if (!bot)
420 return "*";
421 else if (bot->uplink == (tand_t *) 1)
422 return botnetnick;
423 else
424 return bot->uplink->bot;
425 }
426
427 /* Modern version of 'whom' (use local data)
428 */
429 void answer_local_whom(int idx, int chan)
430 {
431 char format[81];
432 char c, idle[40];
433 int i, t, nicklen, botnicklen, total = 0;
434
435 if (chan == -1)
436 dprintf(idx, "%s (+: %s, *: %s)\n", BOT_BOTNETUSERS, BOT_PARTYLINE,
437 BOT_LOCALCHAN);
438 else if (chan > 0) {
439 simple_sprintf(idle, "assoc %d", chan);
440 if ((Tcl_Eval(interp, idle) != TCL_OK) || tcl_resultempty())
441 dprintf(idx, "%s %s%d:\n", BOT_USERSONCHAN,
442 (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
443 else
444 dprintf(idx, "%s '%s%s' (%s%d):\n", BOT_USERSONCHAN,
445 (chan < GLOBAL_CHANS) ? "" : "*", tcl_resultstring(),
446 (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
447 }
448 /* Find longest nick and botnick */
449 nicklen = botnicklen = 0;
450 for (i = 0; i < dcc_total; i++)
451 if (dcc[i].type == &DCC_CHAT) {
452 if ((chan == -1) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
453 t = strlen(dcc[i].nick);
454 if (t > nicklen)
455 nicklen = t;
456 t = strlen(botnetnick);
457 if (t > botnicklen)
458 botnicklen = t;
459 }
460 }
461 for (i = 0; i < parties; i++) {
462 if ((chan == -1) || ((chan >= 0) && (party[i].chan == chan))) {
463 t = strlen(party[i].nick);
464 if (t > nicklen)
465 nicklen = t;
466 t = strlen(party[i].bot);
467 if (t > botnicklen)
468 botnicklen = t;
469 }
470 }
471 if (nicklen < 9)
472 nicklen = 9;
473 if (botnicklen < 9)
474 botnicklen = 9;
475
476 egg_snprintf(format, sizeof format, "%%-%us %%-%us %%s\n",
477 nicklen, botnicklen);
478 dprintf(idx, format, " Nick", " Bot", " Host");
479 dprintf(idx, format, "----------", "---------", "--------------------");
480 egg_snprintf(format, sizeof format, "%%c%%-%us %%c %%-%us %%s%%s\n",
481 nicklen, botnicklen);
482 for (i = 0; i < dcc_total; i++)
483 if (dcc[i].type == &DCC_CHAT) {
484 if ((chan == -1) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
485 c = geticon(i);
486 if (c == '-')
487 c = ' ';
488 if (now - dcc[i].timeval > 300) {
489 unsigned long days, hrs, mins;
490
491 days = (now - dcc[i].timeval) / 86400;
492 hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
493 mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
494 if (days > 0)
495 sprintf(idle, " [idle %lud%luh]", days, hrs);
496 else if (hrs > 0)
497 sprintf(idle, " [idle %luh%lum]", hrs, mins);
498 else
499 sprintf(idle, " [idle %lum]", mins);
500 } else
501 idle[0] = 0;
502 total++;
503 dprintf(idx, format, c, dcc[i].nick,
504 (dcc[i].u.chat->channel == 0) && (chan == -1) ? '+' :
505 (dcc[i].u.chat->channel >= GLOBAL_CHANS) &&
506 (chan == -1) ? '*' : ' ', botnetnick, dcc[i].host, idle);
507 if (dcc[i].u.chat->away != NULL)
508 dprintf(idx, " AWAY: %s\n", dcc[i].u.chat->away);
509 }
510 }
511 for (i = 0; i < parties; i++) {
512 if ((chan == -1) || ((chan >= 0) && (party[i].chan == chan))) {
513 c = party[i].flag;
514 if (c == '-')
515 c = ' ';
516 if (party[i].timer == 0L)
517 strcpy(idle, " [idle?]");
518 else if (now - party[i].timer > 300) {
519 unsigned long days, hrs, mins;
520
521 days = (now - party[i].timer) / 86400;
522 hrs = ((now - party[i].timer) - (days * 86400)) / 3600;
523 mins = ((now - party[i].timer) - (hrs * 3600)) / 60;
524 if (days > 0)
525 sprintf(idle, " [idle %lud%luh]", days, hrs);
526 else if (hrs > 0)
527 sprintf(idle, " [idle %luh%lum]", hrs, mins);
528 else
529 sprintf(idle, " [idle %lum]", mins);
530 } else
531 idle[0] = 0;
532 total++;
533 dprintf(idx, format, c, party[i].nick,
534 (party[i].chan == 0) && (chan == -1) ? '+' : ' ',
535 party[i].bot, party[i].from, idle);
536 if (party[i].status & PLSTAT_AWAY)
537 dprintf(idx, " %s: %s\n", MISC_AWAY,
538 party[i].away ? party[i].away : "");
539 }
540 }
541 dprintf(idx, "Total users: %d\n", total);
542 }
543
544 /* Show z a list of all bots connected
545 */
546 void tell_bots(int idx)
547 {
548 char s[512];
549 int i;
550 tand_t *bot;
551
552 if (!tands) {
553 dprintf(idx, "%s\n", BOT_NOBOTSLINKED);
554 return;
555 }
556 strcpy(s, botnetnick);
557 i = strlen(botnetnick);
558
559 for (bot = tandbot; bot; bot = bot->next) {
560 if (i > (500 - HANDLEN)) {
561 dprintf(idx, "Bots: %s\n", s);
562 s[0] = 0;
563 i = 0;
564 }
565 if (i) {
566 s[i++] = ',';
567 s[i++] = ' ';
568 }
569 strcpy(s + i, bot->bot);
570 i += strlen(bot->bot);
571 }
572 if (s[0])
573 dprintf(idx, "Bots: %s\n", s);
574 dprintf(idx, "%s: %d\n", MISC_TOTAL, tands + 1);
575 }
576
577 /* Show a simpleton bot tree
578 */
579 void tell_bottree(int idx, int showver)
580 {
581 char s[161];
582 tand_t *last[20], *this, *bot, *bot2 = NULL;
583 int lev = 0, more = 1, mark[20], ok, cnt, i, imark;
584 char work[1024];
585 int tothops = 0;
586
587 if (tands == 0) {
588 dprintf(idx, "%s\n", BOT_NOBOTSLINKED);
589 return;
590 }
591 s[0] = 0;
592 i = 0;
593
594 for (bot = tandbot; bot; bot = bot->next)
595 if (!bot->uplink) {
596 if (i) {
597 s[i++] = ',';
598 s[i++] = ' ';
599 }
600 strcpy(s + i, bot->bot);
601 i += strlen(bot->bot);
602 }
603 if (s[0])
604 dprintf(idx, "(%s %s)\n", BOT_NOTRACEINFO, s);
605 if (showver)
606 dprintf(idx, "%s (%d.%d.%d.%d)\n", botnetnick,
607 egg_numver / 1000000,
608 egg_numver % 1000000 / 10000,
609 egg_numver % 10000 / 100, egg_numver % 100);
610 else
611 dprintf(idx, "%s\n", botnetnick);
612 this = (tand_t *) 1;
613 work[0] = 0;
614 while (more) {
615 if (lev == 20) {
616 dprintf(idx, "\n%s\n", BOT_COMPLEXTREE);
617 return;
618 }
619 cnt = 0;
620 tothops += lev;
621 for (bot = tandbot; bot; bot = bot->next)
622 if (bot->uplink == this)
623 cnt++;
624 if (cnt) {
625 imark = 0;
626 for (i = 0; i < lev; i++) {
627 if (mark[i])
628 strcpy(work + imark, " | ");
629 else
630 strcpy(work + imark, " ");
631 imark += 5;
632 }
633 if (cnt > 1)
634 strcpy(work + imark, " |-");
635 else
636 strcpy(work + imark, " `-");
637 s[0] = 0;
638 bot = tandbot;
639 while (!s[0]) {
640 if (bot->uplink == this) {
641 if (bot->ver) {
642 i = sprintf(s, "%c%s", bot->share, bot->bot);
643 if (showver)
644 sprintf(s + i, " (%d.%d.%d.%d)",
645 bot->ver / 1000000,
646 bot->ver % 1000000 / 10000,
647 bot->ver % 10000 / 100, bot->ver % 100);
648 } else
649 sprintf(s, "-%s", bot->bot);
650 } else
651 bot = bot->next;
652 }
653 dprintf(idx, "%s%s\n", work, s);
654 if (cnt > 1)
655 mark[lev] = 1;
656 else
657 mark[lev] = 0;
658 work[0] = 0;
659 last[lev] = this;
660 this = bot;
661 lev++;
662 more = 1;
663 } else {
664 while (cnt == 0) {
665 /* No subtrees from here */
666 if (lev == 0) {
667 dprintf(idx, "(( tree error ))\n");
668 return;
669 }
670 ok = 0;
671 for (bot = tandbot; bot; bot = bot->next) {
672 if (bot->uplink == last[lev - 1]) {
673 if (this == bot)
674 ok = 1;
675 else if (ok) {
676 cnt++;
677 if (cnt == 1) {
678 bot2 = bot;
679 if (bot->ver) {
680 i = sprintf(s, "%c%s", bot->share, bot->bot);
681 if (showver)
682 sprintf(s + i, " (%d.%d.%d.%d)",
683 bot->ver / 1000000,
684 bot->ver % 1000000 / 10000,
685 bot->ver % 10000 / 100, bot->ver % 100);
686 } else
687 sprintf(s, "-%s", bot->bot);
688 }
689 }
690 }
691 }
692 if (cnt) {
693 imark = 0;
694 for (i = 1; i < lev; i++) {
695 if (mark[i - 1])
696 strcpy(work + imark, " | ");
697 else
698 strcpy(work + imark, " ");
699 imark += 5;
700 }
701 more = 1;
702 if (cnt > 1)
703 dprintf(idx, "%s |-%s\n", work, s);
704 else
705 dprintf(idx, "%s `-%s\n", work, s);
706 this = bot2;
707 work[0] = 0;
708 if (cnt > 1)
709 mark[lev - 1] = 1;
710 else
711 mark[lev - 1] = 0;
712 } else {
713 /* This was the last child */
714 lev--;
715 if (lev == 0) {
716 more = 0;
717 cnt = 999;
718 } else {
719 more = 1;
720 this = last[lev];
721 }
722 }
723 }
724 }
725 }
726 /* Hop information: (9d) */
727 dprintf(idx, "Average hops: %3.1f, total bots: %d\n",
728 ((float) tothops) / ((float) tands), tands + 1);
729 }
730
731 /* Dump list of links to a new bot
732 */
733 void dump_links(int z)
734 {
735 register int i, l;
736 char x[1024];
737 tand_t *bot;
738
739 for (bot = tandbot; bot; bot = bot->next) {
740 char *p;
741
742 if (bot->uplink == (tand_t *) 1)
743 p = botnetnick;
744 else
745 p = bot->uplink->bot;
746 #ifndef NO_OLD_BOTNET
747 if (b_numver(z) < NEAT_BOTNET)
748 l = simple_sprintf(x, "nlinked %s %s %c%d\n", bot->bot,
749 p, bot->share, bot->ver);
750 else
751 #endif
752 l = simple_sprintf(x, "n %s %s %c%D\n", bot->bot, p,
753 bot->share, bot->ver);
754 tputs(dcc[z].sock, x, l);
755 }
756 if (!(bot_flags(dcc[z].user) & BOT_ISOLATE)) {
757 /* Dump party line members */
758 for (i = 0; i < dcc_total; i++) {
759 if (dcc[i].type == &DCC_CHAT) {
760 if ((dcc[i].u.chat->channel >= 0) &&
761 (dcc[i].u.chat->channel < GLOBAL_CHANS)) {
762 #ifndef NO_OLD_BOTNET
763 if (b_numver(z) < NEAT_BOTNET)
764 l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
765 botnetnick, dcc[i].nick,
766 dcc[i].u.chat->channel, geticon(i),
767 dcc[i].sock, dcc[i].host);
768 else
769 #endif
770 l = simple_sprintf(x, "j !%s %s %D %c%D %s\n",
771 botnetnick, dcc[i].nick,
772 dcc[i].u.chat->channel, geticon(i),
773 dcc[i].sock, dcc[i].host);
774 tputs(dcc[z].sock, x, l);
775 #ifndef NO_OLD_BOTNET
776 if (b_numver(z) < NEAT_BOTNET) {
777 if (dcc[i].u.chat->away) {
778 l = simple_sprintf(x, "away %s %d %s\n", botnetnick,
779 dcc[i].sock, dcc[i].u.chat->away);
780 tputs(dcc[z].sock, x, l);
781 }
782 l = simple_sprintf(x, "idle %s %d %d\n", botnetnick,
783 dcc[i].sock, now - dcc[i].timeval);
784 } else
785 #endif
786 l = simple_sprintf(x, "i %s %D %D %s\n", botnetnick,
787 dcc[i].sock, now - dcc[i].timeval,
788 dcc[i].u.chat->away ? dcc[i].u.chat->away : "");
789 tputs(dcc[z].sock, x, l);
790 }
791 }
792 }
793 for (i = 0; i < parties; i++) {
794 #ifndef NO_OLD_BOTNET
795 if (b_numver(z) < NEAT_BOTNET)
796 l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
797 party[i].bot, party[i].nick,
798 party[i].chan, party[i].flag,
799 party[i].sock, party[i].from);
800 else
801 #endif
802 l = simple_sprintf(x, "j %s %s %D %c%D %s\n",
803 party[i].bot, party[i].nick,
804 party[i].chan, party[i].flag,
805 party[i].sock, party[i].from);
806 tputs(dcc[z].sock, x, l);
807 if ((party[i].status & PLSTAT_AWAY) || (party[i].timer != 0)) {
808 #ifndef NO_OLD_BOTNET
809 if (b_numver(z) < NEAT_BOTNET) {
810 if (party[i].status & PLSTAT_AWAY) {
811 l = simple_sprintf(x, "away %s %d %s\n", party[i].bot,
812 party[i].sock, party[i].away);
813 tputs(dcc[z].sock, x, l);
814 }
815 l = simple_sprintf(x, "idle %s %d %d\n", party[i].bot,
816 party[i].sock, now - party[i].timer);
817 } else
818 #endif
819 l = simple_sprintf(x, "i %s %D %D %s\n", party[i].bot,
820 party[i].sock, now - party[i].timer,
821 party[i].away ? party[i].away : "");
822 tputs(dcc[z].sock, x, l);
823 }
824 }
825 }
826 }
827
828 int in_chain(char *who)
829 {
830 if (findbot(who))
831 return 1;
832 if (!egg_strcasecmp(who, botnetnick))
833 return 1;
834 return 0;
835 }
836
837 int bots_in_subtree(tand_t *bot)
838 {
839 int nr = 1;
840 tand_t *b;
841
842 if (!bot)
843 return 0;
844 for (b = tandbot; b; b = b->next) {
845 if (b->bot && (b->uplink == bot)) {
846 nr += bots_in_subtree(b);
847 }
848 }
849 return nr;
850 }
851
852 int users_in_subtree(tand_t *bot)
853 {
854 int i, nr;
855 tand_t *b;
856
857 nr = 0;
858 if (!bot)
859 return 0;
860 for (i = 0; i < parties; i++)
861 if (!egg_strcasecmp(party[i].bot, bot->bot))
862 nr++;
863 for (b = tandbot; b; b = b->next)
864 if (b->bot && (b->uplink == bot))
865 nr += users_in_subtree(b);
866 return nr;
867 }
868
869 /* Break link with a tandembot
870 */
871 int botunlink(int idx, char *nick, char *reason, char *from)
872 {
873 char s[20];
874 register int i;
875 int bots, users;
876 tand_t *bot;
877
878 if (nick[0] == '*')
879 dprintf(idx, "%s\n", BOT_UNLINKALL);
880 for (i = 0; i < dcc_total; i++) {
881 if ((nick[0] == '*') || !egg_strcasecmp(dcc[i].nick, nick)) {
882 if (dcc[i].type == &DCC_FORK_BOT) {
883 if (idx >= 0)
884 dprintf(idx, "%s: %s -> %s.\n", BOT_KILLLINKATTEMPT,
885 dcc[i].nick, dcc[i].host);
886 putlog(LOG_BOTS, "*", "%s: %s -> %s:%d",
887 BOT_KILLLINKATTEMPT, dcc[i].nick, dcc[i].host, dcc[i].port);
888 killsock(dcc[i].sock);
889 lostdcc(i);
890 if (nick[0] != '*')
891 return 1;
892 } else if (dcc[i].type == &DCC_BOT_NEW) {
893 if (idx >= 0)
894 dprintf(idx, "%s %s.\n", BOT_ENDLINKATTEMPT, dcc[i].nick);
895 putlog(LOG_BOTS, "*", "%s %s @ %s:%d",
896 "Stopped trying to link", dcc[i].nick, dcc[i].host, dcc[i].port);
897 killsock(dcc[i].sock);
898 lostdcc(i);
899 if (nick[0] != '*')
900 return 1;
901 } else if (dcc[i].type == &DCC_BOT) {
902 char s[1024];
903
904 if (idx >= 0)
905 dprintf(idx, "%s %s.\n", BOT_BREAKLINK, dcc[i].nick);
906 else if ((idx == -3) && (b_status(i) & STAT_SHARE) && !share_unlinks)
907 return -1;
908 bot = findbot(dcc[i].nick);
909 bots = bots_in_subtree(bot);
910 users = users_in_subtree(bot);
911 if (reason && reason[0]) {
912 simple_sprintf(s, "%s %s (%s (%s)) (lost %d bot%s and %d user%s)",
913 BOT_UNLINKEDFROM, dcc[i].nick, reason, from, bots,
914 (bots != 1) ? "s" : "", users, (users != 1) ?
915 "s" : "");
916 dprintf(i, "bye %s\n", reason);
917 } else {
918 simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
919 BOT_UNLINKEDFROM, dcc[i].nick, from, bots,
920 (bots != 1) ? "s" : "", users,
921 (users != 1) ? "s" : "");
922 dprintf(i, "bye No reason\n");
923 }
924 chatout("*** %s\n", s);
925 botnet_send_unlinked(i, dcc[i].nick, s);
926 killsock(dcc[i].sock);
927 lostdcc(i);
928 if (nick[0] != '*')
929 return 1;
930 }
931 }
932 }
933 if (idx >= 0 && nick[0] != '*')
934 dprintf(idx, "%s\n", BOT_NOTCONNECTED);
935 if (nick[0] != '*') {
936 bot = findbot(nick);
937 if (bot) {
938 /* The internal bot list is desynched from the dcc list
939 * sometimes. While we still search for the bug, provide
940 * an easy way to clear out those `ghost'-bots.
941 * Fabian (2000-08-02) */
942 char *ghost = "BUG!!: Found bot `%s' in internal bot list, but it\n"
943 " shouldn't have been there! Removing.\n"
944 " This is a known bug we haven't fixed yet. If this\n"
945 " bot is the newest eggdrop version available and you\n"
946 " know a *reliable* way to reproduce the bug, please\n"
947 " contact us - we need your help!\n";
948 if (idx >= 0)
949 dprintf(idx, ghost, nick);
950 else
951 putlog(LOG_MISC, "*", ghost, nick);
952 rembot(bot->bot);
953 return 1;
954 }
955 }
956 if (nick[0] == '*') {
957 dprintf(idx, "%s\n", BOT_WIPEBOTTABLE);
958 while (tandbot)
959 rembot(tandbot->bot);
960 while (parties) {
961 parties--;
962 /* Assert? */
963 if (party[i].chan >= 0)
964 check_tcl_chpt(party[i].bot, party[i].nick, party[i].sock,
965 party[i].chan);
966 }
967 strcpy(s, "killassoc &");
968 Tcl_Eval(interp, s);
969 }
970 return 0;
971 }
972
973 static void botlink_resolve_success(int);
974 static void botlink_resolve_failure(int);
975
976 /* Link to another bot
977 */
978 int botlink(char *linker, int idx, char *nick)
979 {
980 struct bot_addr *bi;
981 struct userrec *u;
982 register int i;
983
984 u = get_user_by_handle(userlist, nick);
985 if (!u || !(u->flags & USER_BOT)) {
986 if (idx >= 0)
987 dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
988 } else if (!egg_strcasecmp(nick, botnetnick)) {
989 if (idx >= 0)
990 dprintf(idx, "%s\n", BOT_CANTLINKMYSELF);
991 } else if (in_chain(nick) && (idx != -3)) {
992 if (idx >= 0)
993 dprintf(idx, "%s\n", BOT_ALREADYLINKED);
994 } else {
995 for (i = 0; i < dcc_total; i++)
996 if ((dcc[i].user == u) &&
997 ((dcc[i].type == &DCC_FORK_BOT) || (dcc[i].type == &DCC_BOT_NEW))) {
998 if (idx >= 0)
999 dprintf(idx, "%s\n", BOT_ALREADYLINKING);
1000 return 0;
1001 }
1002 /* Address to connect to is in 'info' */
1003 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1004 if (!bi || !strlen(bi->address) || !bi->telnet_port ||
1005 (bi->telnet_port <= 0)) {
1006 if (idx >= 0) {
1007 dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
1008 dprintf(idx, "%s .chaddr %s %s\n",
1009 MISC_USEFORMAT, nick, MISC_CHADDRFORMAT);
1010 }
1011 } else if (dcc_total == max_dcc && increase_socks_max()) {
1012 if (idx >= 0)
1013 dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
1014 } else {
1015 correct_handle(nick);
1016
1017 if (idx > -2)
1018 #ifdef IPV6
1019 {
1020 if (strchr(bi->address, ':'))
1021 putlog(LOG_BOTS, "*", "%s %s at [%s]:%d ...", BOT_LINKING, nick,
1022 bi->address, bi->telnet_port);
1023 else
1024 putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
1025 bi->address, bi->telnet_port);
1026 }
1027 #else
1028 putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
1029 bi->address, bi->telnet_port);
1030 #endif
1031 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1032 dcc[i].timeval = now;
1033 dcc[i].port = bi->telnet_port;
1034 dcc[i].user = u;
1035 strcpy(dcc[i].nick, nick);
1036 strcpy(dcc[i].host, bi->address);
1037 dcc[i].u.dns->ibuf = idx;
1038 dcc[i].u.dns->cptr = get_data_ptr(strlen(linker) + 1);
1039 strcpy(dcc[i].u.dns->cptr, linker);
1040 dcc[i].u.dns->host = get_data_ptr(strlen(dcc[i].host) + 1);
1041 strcpy(dcc[i].u.dns->host, dcc[i].host);
1042 dcc[i].u.dns->dns_success = botlink_resolve_success;
1043 dcc[i].u.dns->dns_failure = botlink_resolve_failure;
1044 dcc[i].u.dns->dns_type = RES_IPBYHOST;
1045 dcc[i].u.dns->type = &DCC_FORK_BOT;
1046 dcc_dnsipbyhost(bi->address);
1047 return 1;
1048 }
1049 }
1050 return 0;
1051 }
1052
1053 static void botlink_resolve_failure(int i)
1054 {
1055 char s[81];
1056
1057 putlog(LOG_BOTS, "*", DCC_LINKFAIL, dcc[i].nick);
1058 strcpy(s, dcc[i].nick);
1059 nfree(dcc[i].u.dns->cptr);
1060 lostdcc(i);
1061 autolink_cycle(s); /* Check for more auto-connections */
1062 }
1063
1064 static void botlink_resolve_success(int i)
1065 {
1066 int idx = dcc[i].u.dns->ibuf;
1067 char *linker = dcc[i].u.dns->cptr;
1068
1069 changeover_dcc(i, &DCC_FORK_BOT, sizeof(struct bot_info));
1070 dcc[i].timeval = now;
1071 strcpy(dcc[i].u.bot->linker, linker);
1072 strcpy(dcc[i].u.bot->version, "(primitive bot)");
1073 dcc[i].u.bot->numver = idx;
1074 dcc[i].u.bot->port = dcc[i].port; /* Remember where i started */
1075 nfree(linker);
1076 setsnport(dcc[i].sockname, dcc[i].port);
1077 dcc[i].sock = getsock(dcc[i].sockname.family, SOCK_STRONGCONN);
1078 if (dcc[i].sock < 0 ||
1079 open_telnet_raw(dcc[i].sock, &dcc[i].sockname) < 0)
1080 failed_link(i);
1081 }
1082
1083 static void failed_tandem_relay(int idx)
1084 {
1085 int uidx = -1, i;
1086
1087 for (i = 0; i < dcc_total; i++)
1088 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1089 (dcc[i].u.relay->sock == dcc[idx].sock))
1090 uidx = i;
1091 if (uidx < 0) {
1092 putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
1093 dcc[idx].sock, dcc[idx].u.relay->sock);
1094 killsock(dcc[idx].sock);
1095 lostdcc(idx);
1096 return;
1097 }
1098 if (dcc[idx].port >= dcc[idx].u.relay->port + 3) {
1099 struct chat_info *ci = dcc[uidx].u.relay->chat;
1100
1101 dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
1102 dcc[uidx].status = dcc[uidx].u.relay->old_status;
1103 nfree(dcc[uidx].u.relay);
1104 dcc[uidx].u.chat = ci;
1105 dcc[uidx].type = &DCC_CHAT;
1106 killsock(dcc[idx].sock);
1107 lostdcc(idx);
1108 return;
1109 }
1110 killsock(dcc[idx].sock);
1111 if (!dcc[idx].sockname.addrlen)
1112 (void) setsockname(&dcc[idx].sockname, dcc[idx].host, dcc[idx].port, 0);
1113 dcc[idx].sock = getsock(dcc[idx].sockname.family, SOCK_STRONGCONN);
1114 dcc[uidx].u.relay->sock = dcc[idx].sock;
1115 dcc[idx].port++;
1116 dcc[idx].timeval = now;
1117 if (dcc[idx].sock < 0 ||
1118 open_telnet_raw(dcc[idx].sock, &dcc[idx].sockname) < 0)
1119 failed_tandem_relay(idx);
1120 }
1121
1122
1123 static void tandem_relay_resolve_failure(int);
1124 static void tandem_relay_resolve_success(int);
1125
1126 /* Relay to another tandembot
1127 */
1128 void tandem_relay(int idx, char *nick, register int i)
1129 {
1130 struct userrec *u;
1131 struct bot_addr *bi;
1132 struct chat_info *ci;
1133
1134 u = get_user_by_handle(userlist, nick);
1135 if (!u || !(u->flags & USER_BOT)) {
1136 dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
1137 return;
1138 }
1139 if (!egg_strcasecmp(nick, botnetnick)) {
1140 dprintf(idx, "%s\n", BOT_CANTRELAYMYSELF);
1141 return;
1142 }
1143 /* Address to connect to is in 'info' */
1144 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1145 if (!bi || !strlen(bi->address) || !bi->relay_port || (bi->relay_port <= 0)) {
1146 dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
1147 dprintf(idx, "%s .chaddr %s %s\n", MISC_USEFORMAT, nick,
1148 MISC_CHADDRFORMAT);
1149 return;
1150 }
1151 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1152 if (i < 0) {
1153 dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
1154 return;
1155 }
1156
1157 dcc[i].sock = getsock(AF_INET, SOCK_STRONGCONN | SOCK_VIRTUAL);
1158 if (dcc[i].sock < 0) {
1159 lostdcc(i);
1160 dprintf(idx, "%s\n", MISC_NOFREESOCK);
1161 return;
1162 }
1163
1164 dcc[i].port = bi->relay_port;
1165 dcc[i].addr = 0L;
1166 strcpy(dcc[i].nick, nick);
1167 dcc[i].user = u;
1168 strcpy(dcc[i].host, bi->address);
1169 #ifdef IPV6
1170 if (strchr(bi->address, ':'))
1171 dprintf(idx, "%s %s @ [%s]:%d ...\n", BOT_CONNECTINGTO, nick,
1172 bi->address, bi->relay_port);
1173 else
1174 #endif
1175 dprintf(idx, "%s %s @ %s:%d ...\n", BOT_CONNECTINGTO, nick,
1176 bi->address, bi->relay_port);
1177 dprintf(idx, "%s\n", BOT_BYEINFO1);
1178 dcc[idx].type = &DCC_PRE_RELAY;
1179 ci = dcc[idx].u.chat;
1180 dcc[idx].u.relay = get_data_ptr(sizeof(struct relay_info));
1181 dcc[idx].u.relay->chat = ci;
1182 dcc[idx].u.relay->old_status = dcc[idx].status;
1183 dcc[i].timeval = now;
1184 dcc[idx].u.relay->sock = dcc[i].sock;
1185 dcc[i].u.dns->ibuf = dcc[idx].sock;
1186 dcc[i].u.dns->host = get_data_ptr(strlen(bi->address) + 1);
1187 strcpy(dcc[i].u.dns->host, bi->address);
1188 dcc[i].u.dns->dns_success = tandem_relay_resolve_success;
1189 dcc[i].u.dns->dns_failure = tandem_relay_resolve_failure;
1190 dcc[i].u.dns->dns_type = RES_IPBYHOST;
1191 dcc[i].u.dns->type = &DCC_FORK_RELAY;
1192 dcc_dnsipbyhost(bi->address);
1193 }
1194
1195 static void tandem_relay_resolve_failure(int idx)
1196 {
1197 struct chat_info *ci;
1198 register int uidx = -1, i;
1199
1200 for (i = 0; i < dcc_total; i++)
1201 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1202 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1203 uidx = i;
1204 break;
1205 }
1206 if (uidx < 0) {
1207 putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
1208 dcc[idx].sock, dcc[idx].u.relay->sock);
1209 killsock(dcc[idx].sock);
1210 lostdcc(idx);
1211 return;
1212 }
1213 ci = dcc[uidx].u.relay->chat;
1214 dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
1215 dcc[uidx].status = dcc[uidx].u.relay->old_status;
1216 nfree(dcc[uidx].u.relay);
1217 dcc[uidx].u.chat = ci;
1218 dcc[uidx].type = &DCC_CHAT;
1219 killsock(dcc[idx].sock);
1220 lostdcc(idx);
1221 }
1222
1223 static void tandem_relay_resolve_success(int i)
1224 {
1225 int sock = dcc[i].u.dns->ibuf;
1226
1227 changeover_dcc(i, &DCC_FORK_RELAY, sizeof(struct relay_info));
1228 dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info));
1229
1230 dcc[i].u.relay->sock = sock;
1231 dcc[i].u.relay->port = dcc[i].port;
1232 dcc[i].u.relay->chat->away = NULL;
1233 dcc[i].u.relay->chat->msgs_per_sec = 0;
1234 dcc[i].u.relay->chat->con_flags = 0;
1235 dcc[i].u.relay->chat->buffer = NULL;
1236 dcc[i].u.relay->chat->max_line = 0;
1237 dcc[i].u.relay->chat->line_count = 0;
1238 dcc[i].u.relay->chat->current_lines = 0;
1239 dcc[i].timeval = now;
1240 #ifdef IPV6
1241 if (dcc[i].sockname.family == AF_INET6) {
1242 killsock(dcc[i].sock);
1243 dcc[i].sock = getsock(AF_INET6, SOCK_STRONGCONN | SOCK_VIRTUAL);
1244 dcc[i].sockname.addr.s6.sin6_port = htons(dcc[i].port);
1245 dcc[i].u.relay->sock = dcc[i].sock;
1246 } else
1247 #endif
1248 dcc[i].sockname.addr.s4.sin_port = htons(dcc[i].port);
1249 if (open_telnet_raw(dcc[i].sock, &dcc[i].sockname) < 0)
1250 failed_tandem_relay(i);
1251 }
1252
1253 /* Input from user before connect is ready
1254 */
1255 static void pre_relay(int idx, char *buf, register int i)
1256 {
1257 register int tidx = -1;
1258
1259 for (i = 0; i < dcc_total; i++)
1260 if ((dcc[i].type == &DCC_FORK_RELAY) &&
1261 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1262 tidx = i;
1263 break;
1264 }
1265 if (tidx < 0) {
1266 /* Now try to find it among the DNSWAIT sockets instead. */
1267 for (i = 0; i < dcc_total; i++)
1268 if ((dcc[i].type == &DCC_DNSWAIT) &&
1269 (dcc[i].sock == dcc[idx].u.relay->sock)) {
1270 tidx = i;
1271 break;
1272 }
1273 }
1274 if (tidx < 0) {
1275 putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
1276 dcc[idx].sock, dcc[idx].u.relay->sock);
1277 killsock(dcc[idx].sock);
1278 lostdcc(idx);
1279 return;
1280 }
1281 if (!egg_strcasecmp(buf, "*bye*")) {
1282 /* Disconnect */
1283 struct chat_info *ci = dcc[idx].u.relay->chat;
1284
1285 dprintf(idx, "%s %s.\n", BOT_ABORTRELAY1, dcc[tidx].nick);
1286 dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
1287 putlog(LOG_MISC, "*", "%s %s -> %s", BOT_ABORTRELAY3, dcc[idx].nick,
1288 dcc[tidx].nick);
1289 dcc[idx].status = dcc[idx].u.relay->old_status;
1290 nfree(dcc[idx].u.relay);
1291 dcc[idx].u.chat = ci;
1292 dcc[idx].type = &DCC_CHAT;
1293 killsock(dcc[tidx].sock);
1294 lostdcc(tidx);
1295 return;
1296 }
1297 }
1298
1299 /* User disconnected before her relay had finished connecting
1300 */
1301 static void failed_pre_relay(int idx)
1302 {
1303 register int tidx = -1, i;
1304
1305 for (i = 0; i < dcc_total; i++)
1306 if ((dcc[i].type == &DCC_FORK_RELAY) &&
1307 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1308 tidx = i;
1309 break;
1310 }
1311 if (tidx < 0) {
1312 /* Now try to find it among the DNSWAIT sockets instead. */
1313 for (i = 0; i < dcc_total; i++)
1314 if ((dcc[i].type == &DCC_DNSWAIT) &&
1315 (dcc[i].sock == dcc[idx].u.relay->sock)) {
1316 tidx = i;
1317 break;
1318 }
1319 }
1320 if (tidx < 0) {
1321 putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
1322 dcc[idx].sock, dcc[idx].u.relay->sock);
1323 killsock(dcc[idx].sock);
1324 lostdcc(idx);
1325 return;
1326 }
1327 putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
1328 dcc[idx].host, dcc[idx].port);
1329 putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPINGRELAY, dcc[tidx].nick);
1330 if ((dcc[tidx].sock != STDOUT) || backgrd) {
1331 if (idx > tidx) {
1332 int t = tidx;
1333
1334 tidx = idx;
1335 idx = t;
1336 }
1337 killsock(dcc[tidx].sock);
1338 lostdcc(tidx);
1339 } else
1340 fatal("Lost my terminal?!", 0);
1341 killsock(dcc[idx].sock);
1342 lostdcc(idx);
1343 }
1344
1345 static void cont_tandem_relay(int idx, char *buf, register int i)
1346 {
1347 register int uidx = -1;
1348 struct relay_info *ri;
1349
1350 for (i = 0; i < dcc_total; i++)
1351 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1352 (dcc[i].u.relay->sock == dcc[idx].sock))
1353 uidx = i;
1354 if (uidx < 0) {
1355 putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
1356 dcc[i].sock, dcc[i].u.relay->sock);
1357 killsock(dcc[i].sock);
1358 lostdcc(i);
1359 return;
1360 }
1361 dcc[idx].type = &DCC_RELAY;
1362 dcc[idx].u.relay->sock = dcc[uidx].sock;
1363 dcc[uidx].u.relay->sock = dcc[idx].sock;
1364 dprintf(uidx, "%s %s ...\n", BOT_RELAYSUCCESS, dcc[idx].nick);
1365 dprintf(uidx, "%s\n\n", BOT_BYEINFO2);
1366 putlog(LOG_MISC, "*", "%s %s -> %s", BOT_RELAYLINK,
1367 dcc[uidx].nick, dcc[idx].nick);
1368 ri = dcc[uidx].u.relay; /* YEAH */
1369 dcc[uidx].type = &DCC_CHAT;
1370 dcc[uidx].u.chat = ri->chat;
1371 if (dcc[uidx].u.chat->channel >= 0) {
1372 chanout_but(-1, dcc[uidx].u.chat->channel, "*** %s %s\n",
1373 dcc[uidx].nick, BOT_PARTYLEFT);
1374 if (dcc[uidx].u.chat->channel < GLOBAL_CHANS)
1375 botnet_send_part_idx(uidx, NULL);
1376 check_tcl_chpt(botnetnick, dcc[uidx].nick, dcc[uidx].sock,
1377 dcc[uidx].u.chat->channel);
1378 }
1379 check_tcl_chof(dcc[uidx].nick, dcc[uidx].sock);
1380 dcc[uidx].type = &DCC_RELAYING;
1381 dcc[uidx].u.relay = ri;
1382 }
1383
1384 static void eof_dcc_relay(int idx)
1385 {
1386 register int j;
1387 struct chat_info *ci;
1388
1389 for (j = 0; j < dcc_total; j++)
1390 if (dcc[j].sock == dcc[idx].u.relay->sock)
1391 break;
1392 if (j == dcc_total) {
1393 killsock(dcc[idx].sock);
1394 lostdcc(idx);
1395 return;
1396 }
1397 dcc[j].status = dcc[j].u.relay->old_status;
1398 /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1399 if (dcc[j].status & STAT_TELNET)
1400 dprintf(j, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1401 putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_ENDRELAY1, dcc[j].nick,
1402 dcc[idx].nick);
1403 dprintf(j, "\n\n*** %s %s\n", BOT_ENDRELAY2, botnetnick);
1404 ci = dcc[j].u.relay->chat;
1405 nfree(dcc[j].u.relay);
1406 dcc[j].u.chat = ci;
1407 dcc[j].type = &DCC_CHAT;
1408 if (dcc[j].u.chat->channel >= 0) {
1409 chanout_but(-1, dcc[j].u.chat->channel, "*** %s %s.\n",
1410 dcc[j].nick, BOT_PARTYREJOINED);
1411 if (dcc[j].u.chat->channel < GLOBAL_CHANS)
1412 botnet_send_join_idx(j, -1);
1413 }
1414 check_tcl_chon(dcc[j].nick, dcc[j].sock);
1415 check_tcl_chjn(botnetnick, dcc[j].nick, dcc[j].u.chat->channel,
1416 geticon(j), dcc[j].sock, dcc[j].host);
1417 killsock(dcc[idx].sock);
1418 lostdcc(idx);
1419 }
1420
1421 static void eof_dcc_relaying(int idx)
1422 {
1423 register int j, x = dcc[idx].u.relay->sock;
1424
1425 putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
1426 dcc[idx].host, dcc[idx].port);
1427 killsock(dcc[idx].sock);
1428 lostdcc(idx);
1429 for (j = 0; (dcc[j].sock != x) || (dcc[j].type == &DCC_FORK_RELAY); j++);
1430 putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPEDRELAY, dcc[j].nick);
1431 killsock(dcc[j].sock);
1432 lostdcc(j); /* Drop connection to the bot */
1433 }
1434
1435 static void dcc_relay(int idx, char *buf, int j)
1436 {
1437 unsigned char *p = (unsigned char *) buf;
1438 int mark;
1439
1440 for (j = 0; dcc[j].sock != dcc[idx].u.relay->sock ||
1441 dcc[j].type != &DCC_RELAYING; j++);
1442 /* If redirecting to a non-telnet user, swallow telnet codes and
1443 * escape sequences. */
1444 if (!(dcc[j].status & STAT_TELNET)) {
1445 while (*p != 0) {
1446 while (*p != 255 && (*p != '\033' || *(p + 1) != '[') && *p != '\r' && *p)
1447 p++; /* Search for IAC, escape sequences and CR. */
1448 if (*p == 255) {
1449 mark = 2;
1450 if (!*(p + 1))
1451 mark = 1; /* Bogus */
1452 if ((*(p + 1) >= 251) || (*(p + 1) <= 254)) {
1453 mark = 3;
1454 if (!*(p + 2))
1455 mark = 2; /* Bogus */
1456 }
1457 strcpy((char *) p, (char *) (p + mark));
1458 } else if (*p == '\033') {
1459 unsigned char *e;
1460
1461 /* Search for the end of the escape sequence. */
1462 for (e = p + 2; *e != 'm' && *e; e++);
1463 strcpy((char *) p, (char *) (e + 1));
1464 } else if (*p == '\r')
1465 strcpy((char *) p, (char *) (p + 1));
1466 }
1467 if (!buf[0])
1468 dprintf(-dcc[idx].u.relay->sock, " \n");
1469 else
1470 dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1471 return;
1472 }
1473 /* Telnet user */
1474 if (!buf[0])
1475 dprintf(-dcc[idx].u.relay->sock, " \r\n");
1476 else
1477 dprintf(-dcc[idx].u.relay->sock, "%s\r\n", buf);
1478 }
1479
1480 static void dcc_relaying(int idx, char *buf, int j)
1481 {
1482 struct chat_info *ci;
1483
1484 if (egg_strcasecmp(buf, "*bye*")) {
1485 dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1486 return;
1487 }
1488 for (j = 0; (dcc[j].sock != dcc[idx].u.relay->sock) ||
1489 (dcc[j].type != &DCC_RELAY); j++);
1490 dcc[idx].status = dcc[idx].u.relay->old_status;
1491 /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1492 if (dcc[idx].status & STAT_TELNET)
1493 dprintf(idx, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1494 dprintf(idx, "\n(%s %s.)\n", BOT_BREAKRELAY, dcc[j].nick);
1495 dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
1496 putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_RELAYBROKEN,
1497 dcc[idx].nick, dcc[j].nick);
1498 if (dcc[idx].u.relay->chat->channel >= 0) {
1499 chanout_but(-1, dcc[idx].u.relay->chat->channel,
1500 "*** %s joined the party line.\n", dcc[idx].nick);
1501 if (dcc[idx].u.relay->chat->channel < GLOBAL_CHANS)
1502 botnet_send_join_idx(idx, -1);
1503 }
1504 ci = dcc[idx].u.relay->chat;
1505 nfree(dcc[idx].u.relay);
1506 dcc[idx].u.chat = ci;
1507 dcc[idx].type = &DCC_CHAT;
1508 check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
1509 if (dcc[idx].u.chat->channel >= 0)
1510 check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
1511 geticon(idx), dcc[idx].sock, dcc[idx].host);
1512 killsock(dcc[j].sock);
1513 lostdcc(j);
1514 }
1515
1516 static void display_relay(int i, char *other)
1517 {
1518 sprintf(other, "rela -> sock %d", dcc[i].u.relay->sock);
1519 }
1520
1521 static void display_relaying(int i, char *other)
1522 {
1523 sprintf(other, ">rly -> sock %d", dcc[i].u.relay->sock);
1524 }
1525
1526 static void display_tandem_relay(int i, char *other)
1527 {
1528 strcpy(other, "other rela");
1529 }
1530
1531 static void display_pre_relay(int i, char *other)
1532 {
1533 strcpy(other, "other >rly");
1534 }
1535
1536 static int expmem_relay(void *x)
1537 {
1538 register struct relay_info *p = (struct relay_info *) x;
1539 int tot = sizeof(struct relay_info);
1540
1541 if (p->chat)
1542 tot += DCC_CHAT.expmem(p->chat);
1543 return tot;
1544 }
1545
1546 static void kill_relay(int idx, void *x)
1547 {
1548 register struct relay_info *p = (struct relay_info *) x;
1549
1550 if (p->chat)
1551 DCC_CHAT.kill(idx, p->chat);
1552 nfree(p);
1553 }
1554
1555 struct dcc_table DCC_RELAY = {
1556 "RELAY",
1557 0, /* Flags */
1558 eof_dcc_relay,
1559 dcc_relay,
1560 NULL,
1561 NULL,
1562 display_relay,
1563 expmem_relay,
1564 kill_relay,
1565 NULL
1566 };
1567
1568 static void out_relay(int idx, char *buf, void *x)
1569 {
1570 register struct relay_info *p = (struct relay_info *) x;
1571
1572 if (p && p->chat)
1573 DCC_CHAT.output(idx, buf, p->chat);
1574 else
1575 tputs(dcc[idx].sock, buf, strlen(buf));
1576 }
1577
1578 struct dcc_table DCC_RELAYING = {
1579 "RELAYING",
1580 0, /* Flags */
1581 eof_dcc_relaying,
1582 dcc_relaying,
1583 NULL,
1584 NULL,
1585 display_relaying,
1586 expmem_relay,
1587 kill_relay,
1588 out_relay
1589 };
1590
1591 struct dcc_table DCC_FORK_RELAY = {
1592 "FORK_RELAY",
1593 0, /* Flags */
1594 failed_tandem_relay,
1595 cont_tandem_relay,
1596 &connect_timeout,
1597 failed_tandem_relay,
1598 display_tandem_relay,
1599 expmem_relay,
1600 kill_relay,
1601 NULL
1602 };
1603
1604 struct dcc_table DCC_PRE_RELAY = {
1605 "PRE_RELAY",
1606 0, /* Flags */
1607 failed_pre_relay,
1608 pre_relay,
1609 NULL,
1610 NULL,
1611 display_pre_relay,
1612 expmem_relay,
1613 kill_relay,
1614 NULL
1615 };
1616
1617 /* Once a minute, send 'ping' to each bot -- no exceptions
1618 */
1619 void check_botnet_pings()
1620 {
1621 int i;
1622 int bots, users;
1623 tand_t *bot;
1624
1625 for (i = 0; i < dcc_total; i++)
1626 if (dcc[i].type == &DCC_BOT)
1627 if (dcc[i].status & STAT_PINGED) {
1628 char s[1024];
1629
1630 putlog(LOG_BOTS, "*", "%s: %s", BOT_PINGTIMEOUT, dcc[i].nick);
1631 bot = findbot(dcc[i].nick);
1632 bots = bots_in_subtree(bot);
1633 users = users_in_subtree(bot);
1634 simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)",
1635 BOT_PINGTIMEOUT, dcc[i].nick, bots,
1636 (bots != 1) ? "s" : "", users, (users != 1) ? "s" : "");
1637 chatout("*** %s\n", s);
1638 botnet_send_unlinked(i, dcc[i].nick, s);
1639 killsock(dcc[i].sock);
1640 lostdcc(i);
1641 }
1642 for (i = 0; i < dcc_total; i++)
1643 if (dcc[i].type == &DCC_BOT) {
1644 botnet_send_ping(i);
1645 dcc[i].status |= STAT_PINGED;
1646 }
1647 for (i = 0; i < dcc_total; i++)
1648 if ((dcc[i].type == &DCC_BOT) && (dcc[i].status & STAT_LEAF)) {
1649 tand_t *bot, *via = findbot(dcc[i].nick);
1650
1651 for (bot = tandbot; bot; bot = bot->next) {
1652 if ((via == bot->via) && (bot != via)) {
1653 /* Not leaflike behavior */
1654 if (dcc[i].status & STAT_WARNED) {
1655 char s[1024];
1656
1657 putlog(LOG_BOTS, "*", "%s %s (%s).", BOT_DISCONNECTED,
1658 dcc[i].nick, BOT_BOTNOTLEAFLIKE);
1659 dprintf(i, "bye %s\n", BOT_BOTNOTLEAFLIKE);
1660 bot = findbot(dcc[i].nick);
1661 bots = bots_in_subtree(bot);
1662 users = users_in_subtree(bot);
1663 simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
1664 BOT_DISCONNECTED, dcc[i].nick, BOT_BOTNOTLEAFLIKE,
1665 bots, (bots != 1) ? "s" : "", users, (users != 1) ?
1666 "s" : "");
1667 chatout("*** %s\n", s);
1668 botnet_send_unlinked(i, dcc[i].nick, s);
1669 killsock(dcc[i].sock);
1670 lostdcc(i);
1671 } else {
1672 botnet_send_reject(i, botnetnick, NULL, bot->bot, NULL, NULL);
1673 dcc[i].status |= STAT_WARNED;
1674 }
1675 } else
1676 dcc[i].status &= ~STAT_WARNED;
1677 }
1678 }
1679 }
1680
1681 void zapfbot(int idx)
1682 {
1683 char s[1024];
1684 int bots, users;
1685 tand_t *bot;
1686
1687 bot = findbot(dcc[idx].nick);
1688 bots = bots_in_subtree(bot);
1689 users = users_in_subtree(bot);
1690 simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", BOT_BOTDROPPED,
1691 dcc[idx].nick, bots, (bots != 1) ? "s" : "", users,
1692 (users != 1) ? "s" : "");
1693 chatout("*** %s\n", s);
1694 botnet_send_unlinked(idx, dcc[idx].nick, s);
1695 killsock(dcc[idx].sock);
1696 lostdcc(idx);
1697 }
1698
1699 void restart_chons()
1700 {
1701 int i;
1702
1703 /* Dump party line members */
1704 for (i = 0; i < dcc_total; i++) {
1705 if (dcc[i].type == &DCC_CHAT) {
1706 check_tcl_chon(dcc[i].nick, dcc[i].sock);
1707 check_tcl_chjn(botnetnick, dcc[i].nick, dcc[i].u.chat->channel,
1708 geticon(i), dcc[i].sock, dcc[i].host);
1709 }
1710 }
1711 for (i = 0; i < parties; i++) {
1712 check_tcl_chjn(party[i].bot, party[i].nick, party[i].chan,
1713 party[i].flag, party[i].sock, party[i].from);
1714 }
1715 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23