/[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.4 - (show annotations) (download) (as text)
Mon Nov 1 22:38:34 2010 UTC (8 years, 5 months ago) by pseudo
Branch: MAIN
CVS Tags: HEAD
Branch point for: gettext
Changes since 1.3: +3 -3 lines
File MIME type: text/x-chdr
Made it possible to specify ssl independently for telnet and user ports when modifying bot addresses.
Changed the syntax of .chaddr and .+bot to use space as a port separator instead of ':'.
Changed the syntax of server list entries to enclose literal IPv6 addresses in square brackets, instead of using a comma to separate the port.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23