/* tandem.c -- handles: keeping track of which bot's connected where in the chain dumping a list of bots or a bot tree to a user channel name associations on the party line rejecting a bot linking, unlinking, and relaying to another bot pinging the bots periodically and checking leaf status asking other bots for ops dprintf'ized, 28nov95 */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include "eggdrop.h" #include "tandem.h" #include "proto.h" /* share user file with tandem bots? */ int share_users=0; /* the ever-confusing passive flag */ int passive=1; /* set to isolate this bot's chat line */ int isolate=0; /* keep track of tandem bots on the botnet */ tand_t *tandbot; /* maximum space for tandem bots currently */ int maxtands=50; /* number of bots on the botnet */ int tands=0; /* channel name-number associations */ assoc_t *assoc=NULL; extern char origbotname[]; extern int serv; extern int dcc_total; extern struct dcc_t dcc[]; extern char botname[]; extern char cx_file[]; extern int cx_line; int expmem_tandem() { assoc_t *a=assoc; int size=0; while (a!=NULL) { size+=sizeof(assoc_t); a=a->next; } size+=(maxtands*sizeof(tand_t)); return size; } void init_tand() { /* grab space for 50 bots for now -- expand later as needed */ maxtands=50; tandbot=(tand_t *)nmalloc(maxtands*sizeof(tand_t)); } /* add a tandem bot to our chain list */ void addbot(who,from) char *who,*from; { context; if (tands==maxtands) { /* expand tandem bot space */ maxtands+=50; tandbot=(tand_t *)nrealloc((void *)tandbot,maxtands*sizeof(tand_t)); } strcpy(tandbot[tands].bot,who); strcpy(tandbot[tands].via,from); if (strcasecmp(who,from)==0) strcpy(tandbot[tands].next,origbotname); else tandbot[tands].next[0]=0; tands++; } /* remove a tandem bot from the chain list */ void rembot(who,from) char *who,*from; { int i,j; context; for (i=0; i */ void unvia(idx,who) int idx; char *who; { int i; context; for (i=0; i */ int nextbot(who) char *who; { int i,j; for (i=0; i500) { s[strlen(s)-2]=0; dprintf(idx,"Bots: %s\n",s); s[0]=0; } } if (s[0]) { s[strlen(s)-2]=0; dprintf(idx,"Bots: %s\n",s); } dprintf(idx,"(total: %d)\n",tands+1); } int get_tands() { return tands; } char *get_tandbot(i) int i; { return tandbot[i].bot; } /* show a simpleton bot tree */ void tell_bottree(idx) int idx; { int i; char s[161],last[20][10],this[10]; int lev=0,more,mark[20],ok,cnt; int tothops=0; context; strcpy(this,origbotname); more=1; if (tands==0) { dprintf(idx,"No bots linked.\n"); return; } s[0]=0; for (i=0; i1) dprintf(idx," |--"); else dprintf(idx," `--"); s[0]=0; i=0; while (!s[0]) { if (strcasecmp(tandbot[i].next,this)==0) strcpy(s,tandbot[i].bot); else i++; } dprintf(idx,"%s\n",s); if (cnt>1) mark[lev]=1; else mark[lev]=0; strcpy(last[lev],this); strcpy(this,s); lev++; more=1; } else { while (cnt==0) { /* no subtrees from here */ if (lev==0) { dprintf(idx,"(( tree error ))\n"); return; } ok=0; for (i=0; i1) dprintf(idx," |--%s\n",this); else dprintf(idx," `--%s\n",this); if (cnt>1) mark[lev-1]=1; else mark[lev-1]=0; } else { /* this was the last child */ lev--; if (lev==0) { more=0; cnt=999; } else { more=1; strcpy(this,last[lev]); } } } } } /* hop information: (9d) */ dprintf(idx,"Average hops: %3.1f, total bots: %d\n", ((float)tothops)/((float)tands),tands+1); } void kill_assoc(chan) int chan; { assoc_t *a=assoc,*last=NULL; while (a!=NULL) { if (a->channel==chan) { if (last!=NULL) last->next=a->next; else assoc=a->next; nfree(a); a=NULL; } else { last=a; a=a->next; } } } /* add a channel association */ void add_assoc(name,chan) char *name; int chan; { assoc_t *a=assoc,*b,*old=NULL; while (a!=NULL) { if ((name[0]!=0) && (strcasecmp(a->name,name)==0)) { kill_assoc(a->channel); add_assoc(name,chan); return; } if (a->channel==chan) { strcpy(a->name,name); return; } a=a->next; } /* add in numerical order */ a=assoc; while (a!=NULL) { if (a->channel > chan) { b=(assoc_t *)nmalloc(sizeof(assoc_t)); b->next=a; b->channel=chan; strcpy(b->name,name); if (old==NULL) assoc=b; else old->next=b; return; } old=a; a=a->next; } /* add at the end */ b=(assoc_t *)nmalloc(sizeof(assoc_t)); b->next=NULL; b->channel=chan; strcpy(b->name,name); if (old==NULL) assoc=b; else old->next=b; } int get_assoc(name) char *name; { assoc_t *a=assoc; while (a!=NULL) { if (strcasecmp(a->name,name)==0) return a->channel; a=a->next; } return -1; } char *get_assoc_name(chan) int chan; { assoc_t *a=assoc; while (a!=NULL) { if (a->channel==chan) return a->name; a=a->next; } return NULL; } void dump_assoc(idx) int idx; { assoc_t *a=assoc; if (a==NULL) { dprintf(idx,"No channel names.\n"); return; } dprintf(idx,"Chan Name\n"); while (a!=NULL) { if (a->name[0]) dprintf(idx,"%5d %s\n",a->channel,a->name); a=a->next; } return; } /* dump list of links to a new bot */ void dump_links(z) int z; { int i; assoc_t *a=assoc; for (i=0; iname[0]) tprintf(z,"assoc %d %s\n",a->channel,a->name); /* else tprintf(z,"assoc %d 0\n",a->channel); */ a=a->next; } } int in_chain(who) char *who; { int i; for (i=0; istatus&STAT_SHARE) { if (dcc[idx].u.tand->status&STAT_GETTING) { j=0; for (i=0; istatus&STAT_SENDING) { j=0; for (i=0; istatus&STAT_GETTING)) && (!(dcc[idx].u.tand->status&STAT_SENDING))) new_tbuf(dcc[idx].nick); } } void reject_bot(who) char *who; { int i; i=nextbot(who); if (i<0) return; if (strcasecmp(dcc[i].nick,who)==0) { /* we're directly connected to the offending bot?! (shudder!) */ putlog(LOG_TAND,"*","Rejecting bot %s",dcc[i].nick); chatout("*** Rejected bot %s\n",dcc[i].nick); tandout_but(i,"chat %s Rejected bot %s\n",origbotname,dcc[i].nick); tandout_but(i,"unlinked %s\n",dcc[i].nick); rembot(dcc[i].nick,dcc[i].nick); unvia(i,dcc[i].nick); cancel_user_xfer(i); tprintf(dcc[i].sock,"bye\n"); close(dcc[i].sock); lostdcc(i); } else { tprintf(dcc[i].sock,"reject %s %s\n",origbotname,who); } } /* disconnect all +a bots because we just got a hub */ void drop_alt_bots() { int atr,i; for (i=0; itype==DCC_TANDEM) { dcc[i].port+=10; kill_proc(i); } } else if (dcc[i].type==DCC_TANDEM_NEW) { close(dcc[i].sock); lostdcc(i); } } } } /* break link with a tandembot */ int tandem_unlink(idx,nick) int idx; char *nick; { int i; context; if (nick[0]=='*') dprintf(idx,"Unlinking all bots ...\n"); for (i=0; itype==DCC_TANDEM)) { if (idx>=0) dprintf(idx,"Killed link attempt to %s.\n",dcc[i].nick); putlog(LOG_TAND,"*","Killed attempt to link %s at %s:%d",dcc[i].nick, dcc[i].host,dcc[i].port); dcc[i].port+=10; /* so it won't just try the next port */ kill_proc(i); if (nick[0]!='*') return 1; } if (dcc[i].type==DCC_TANDEM_NEW) { if (idx>=0) dprintf(idx,"No longer trying to link to %s.\n", dcc[i].nick); putlog(LOG_TAND,"*","Stopped trying to link %s at %s:%d",dcc[i].nick, dcc[i].host,dcc[i].port); close(dcc[i].sock); lostdcc(i); if (nick[0]!='*') return 1; else i--; } if (dcc[i].type==DCC_TANDEM) { if (idx>=0) dprintf(idx,"Breaking link with %s.\n",dcc[i].nick); tprintf(dcc[i].sock,"bye\n"); chatout("*** Unlinked from: %s\n",dcc[i].nick); tandout_but(i,"chat %s Unlinked from: %s\n",origbotname,dcc[i].nick); tandout_but(i,"unlinked %s\n",dcc[i].nick); cancel_user_xfer(i); rembot(dcc[i].nick,dcc[i].nick); unvia(i,dcc[i].nick); close(dcc[i].sock); lostdcc(i); if (nick[0]!='*') return 1; else i--; } } } if ((idx>=0) && (nick[0]!='*')) dprintf(idx,"Not connected to that bot.\n"); return 0; } /* link to another tandembot */ int tandem_link(linker,idx,nick) int idx; char *linker,*nick; { char s[121],*p; int port,i; context; if (!(get_attr_handle(nick) & USER_BOT)) { if (idx>=0) dprintf(idx,"%s is not a known bot.\n",nick); return 0; } if (strcasecmp(nick,origbotname)==0) { if (idx>=0) dprintf(idx,"Link to myself? Oh boy, Freud would have a field day.\n"); return 0; } if ((in_chain(nick)) && (idx>=0)) { dprintf(idx,"That bot is already connected up.\n"); return 0; } /* address to connect to is in 'info' */ get_handle_info(nick,s); if (!s[0]) { if (idx>=0) { dprintf(idx,"No telnet port stored for '%s'.\n",nick); dprintf(idx,"Use: .chaddr %s
:\n",nick); } return 0; } p=strchr(s,':'); if (p==NULL) port=2222; else { *p=0; p++; port=atoi(p); } if (dcc_total==MAXDCC) { if (idx>=0) dprintf(idx,"No more dcc entries left: dcc table is full.\n"); return 0; } context; correct_handle(nick); dcc_total++; i=dcc_total-1; dcc[i].port=port; dcc[i].addr=0L; strcpy(dcc[i].nick,nick); strcpy(dcc[i].host,s); dcc[i].type=DCC_TANDEM; dcc[i].sock=(-1); set_tand(i); dcc[i].u.tand->status=0; dcc[i].u.tand->timer=time(NULL); strcpy(dcc[i].u.tand->linker,linker); strcpy(dcc[i].u.tand->version,"(primitive bot)"); if (idx!=(-1)) putlog(LOG_TAND,"*","Linking to %s at %s ...",nick,s); set_fork(i); dcc[i].sock=idx; /* tandout("trying %s %s\n",origbotname,dcc[i].nick); */ context; fork_link(s,dcc[i].port,i,dcc[i].port); context; return 1; } void cont_tandem_link(sk,idx,stport) int sk,idx,stport; { int z=dcc[idx].sock,i; char s[81]; struct tand_info *ti; context; if (sk>0) { if (dcc[idx].port >= stport+5) { if (dcc[idx].u.fork->u.tand->linker[0]) { sprintf(s,"Couldn't link to %s.",dcc[idx].nick); add_note(dcc[idx].u.fork->u.tand->linker,origbotname,s,-2,0); } if (z!=(-1)) putlog(LOG_TAND,"*","Failed link to %s.",dcc[idx].nick); /* tandout("*trying %s %s\n",origbotname,dcc[idx].nick); */ dcc[idx].sock=dcc[idx].type; dcc[idx].type=DCC_LOST; auto_link_tandem(dcc[idx].nick); /* check for more auto-connections */ return; } dcc[idx].port++; fork_link(dcc[idx].host,dcc[idx].port,idx,stport); return; } context; ti=dcc[idx].u.fork->u.tand; nfree(dcc[idx].u.fork); dcc[idx].u.tand=ti; if (get_attr_handle(dcc[idx].nick) & BOT_HUB) { drop_alt_bots(); /* just those currently in the process of linking */ if (in_chain(dcc[idx].nick)) { i=nextbot(dcc[idx].nick); if (i>0) { chatout("*** Unlinked %s (restructure)\n",dcc[i].nick); tandout_but(i,"chat %s Unlinked %s (restructure)\n",origbotname, dcc[i].nick); tandout_but(i,"unlinked %s\n",dcc[i].nick); rembot(dcc[i].nick,dcc[i].nick); unvia(i,dcc[i].nick); cancel_user_xfer(i); tprintf(dcc[i].sock,"bye\n"); close(dcc[i].sock); dcc[i].type=DCC_LOST; } } } dcc[idx].type=DCC_TANDEM_NEW; get_pass_by_handle(dcc[idx].nick,s); if (strcasecmp(s,"nopass")==0) tprintf(dcc[idx].sock,"%s\n",origbotname); else tprintf(dcc[idx].sock,"%s\n%s\n",origbotname,s); context; return; } /* relay to another tandembot */ void tandem_relay(idx,nick) int idx; char *nick; { char s[121],*p; int port,i; struct chat_info *ci; context; if (!(get_attr_handle(nick) & USER_BOT)) { dprintf(idx,"%s is not a listed bot.\n",nick); return; } if (strcasecmp(nick,origbotname)==0) { dprintf(idx,"Relay to myself? What on EARTH would be the point?!\n"); return; } /* address to connect to is in 'info' */ get_handle_info(nick,s); if (!s[0]) { dprintf(idx,"No telnet port stored for '%s'.\n",nick); dprintf(idx,"Use: .chaddr %s
:\n",nick); return; } p=strchr(s,':'); if (p==NULL) port=2222; else { *p=0; p++; port=atoi(p); } if (dcc_total==MAXDCC) { dprintf(idx,"No more dcc table entries available.\n"); return; } dcc_total++; i=dcc_total-1; dcc[i].port=port; dcc[i].addr=0L; strcpy(dcc[i].nick,nick); strcpy(dcc[i].host,s); dcc[i].type=DCC_RELAY; dcc[i].sock=(-1); set_new_relay(i); dcc[i].u.relay->chat->away=NULL; dcc[i].u.relay->chat->status=0; dcc[i].u.relay->chat->timer=time(NULL); dcc[i].u.relay->chat->msgs_per_sec=0; dcc[i].u.relay->chat->con_flags=0; dprintf(idx,"Connecting to %s at %s ...\n",nick,s); ci=dcc[idx].u.chat; set_relay(idx); dcc[idx].u.relay->chat=ci; dcc[idx].type=DCC_RELAY; set_fork(idx); set_fork(i); fork_relay(s,dcc[i].port,i,dcc[i].port,idx); } void cont_tandem_relay(sk,idx,stport,uidx) int sk,idx,stport,uidx; { struct relay_info *ri; context; if (sk>0) { if (dcc[idx].port >= stport+5) { struct chat_info *ci=dcc[uidx].u.fork->u.relay->chat; dprintf(uidx,"Could not link to %s.\n",dcc[idx].nick); nfree(dcc[uidx].u.fork->u.relay); nfree(dcc[uidx].u.fork); dcc[uidx].u.chat=ci; dcc[uidx].type=DCC_CHAT; dcc[idx].sock=dcc[idx].type; dcc[idx].type=DCC_LOST; return; } dcc[idx].port++; fork_relay(dcc[idx].host,dcc[idx].port,idx,stport,uidx); return; } dprintf(uidx,"Success!\n\n"); dprintf(uidx,"NOW CONNECTED TO RELAY BOT %s ...\n",dcc[idx].nick); dprintf(uidx,"(You can type *BYE* to prematurely close the connection.)\n\n"); ri=dcc[idx].u.fork->u.relay; nfree(dcc[idx].u.fork); dcc[idx].u.relay=ri; ri=dcc[uidx].u.fork->u.relay; nfree(dcc[uidx].u.fork); dcc[uidx].u.relay=ri; dcc[uidx].type=DCC_RELAYING; dcc[idx].type=DCC_RELAY; dcc[idx].u.relay->sock=dcc[uidx].sock; dcc[uidx].u.relay->sock=dcc[idx].sock; putlog(LOG_MISC,"*","Relay link: %s -> %s",dcc[uidx].nick,dcc[idx].nick); if (dcc[uidx].u.relay->chat->channel>=0) chanout2(dcc[uidx].u.relay->chat->channel,"%s left the party line.\n", dcc[uidx].nick); } /* once a monute, send 'ping' to each bot -- no exceptions */ void check_botnet_pings() { int i,j; time_t now=time(NULL); context; for (i=0; istatus&STAT_PINGED) { putlog(LOG_TAND,"*","Ping timeout: %s",dcc[i].nick); chatout("*** Ping timeout: %s\n",dcc[i].nick); tandout_but(i,"chat %s Ping timeout: %s\n",origbotname,dcc[i].nick); tandout_but(i,"unlinked %s\n",dcc[i].nick); rembot(dcc[i].nick,dcc[i].nick); unvia(i,dcc[i].nick); cancel_user_xfer(i); close(dcc[i].sock); lostdcc(i); } for (i=0; istatus|=STAT_PINGED; } for (i=0; istatus&STAT_OFFERED) if (now-dcc[i].u.tand->timer > 120) { tprintf(dcc[i].sock,"userfile?\n"); flush_tbuf(dcc[i].nick); /* ^ send it again in case they missed it */ } for (i=0; istatus&STAT_LEAF)) { for (j=0; jstatus&STAT_WARNED) { putlog(LOG_TAND,"*","No longer tolerating %s acting like a hub.", dcc[i].nick); tprintf(dcc[i].sock,"bye\n"); chatout("*** Disconnected %s (unleaflike behavior)\n", dcc[i].nick); tandout_but(i,"chat %s Disconnected %s (unleaflike behavior)\n", origbotname,dcc[i].nick); tandout_but(i,"unlinked %s\n",dcc[i].nick); cancel_user_xfer(i); rembot(dcc[i].nick,dcc[i].nick); unvia(i,dcc[i].nick); close(dcc[i].sock); lostdcc(i); } else { tprintf(dcc[i].sock,"reject %s %s\n",origbotname,tandbot[j].bot); dcc[i].u.tand->status|=STAT_WARNED; } } else dcc[i].u.tand->status&=~STAT_WARNED; } } }