X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/3ab4edabaa806b55ceffcf75a955ae7f578a2e13..7e032dc63479ed3d0b76fe71c05303fbe7dbc53a:/proxyscan/proxyscan.c diff --git a/proxyscan/proxyscan.c b/proxyscan/proxyscan.c index 21068648..33d6b836 100644 --- a/proxyscan/proxyscan.c +++ b/proxyscan/proxyscan.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "../core/error.h" #include "../core/events.h" @@ -26,6 +27,7 @@ #include "../localuser/localuserchannel.h" #include "../core/nsmalloc.h" #include "../lib/irc_ipv6.h" +#include "../glines/glines.h" MODULE_VERSION("") @@ -39,6 +41,8 @@ MODULE_VERSION("") scan *scantable[SCANHASHSIZE]; +CommandTree *ps_commands; + int listenfd; int activescans; int maxscans; @@ -50,6 +54,7 @@ int glinedhosts; time_t ps_starttime; int ps_cache_ext; int ps_extscan_ext; +int ps_ready; int numscans; /* number of scan types currently valid */ scantype thescans[PSCAN_MAXSCANS]; @@ -81,18 +86,28 @@ void handlescansock(int fd, short events); void timeoutscansock(void *arg); void proxyscan_newnick(int hooknum, void *arg); void proxyscan_lostnick(int hooknum, void *arg); +void proxyscan_onconnect(int hooknum, void *arg); void proxyscanuserhandler(nick *target, int message, void **params); void registerproxyscannick(); void killsock(scan *sp, int outcome); void killallscans(); void proxyscanstats(int hooknum, void *arg); void sendlagwarning(); -void proxyscandostatus(nick *np); -void proxyscandebug(nick *np); void proxyscan_newip(nick *np, unsigned long ip); int proxyscan_addscantype(int type, int port); int proxyscan_delscantype(int type, int port); +int proxyscandostatus(void *sender, int cargc, char **cargv); +int proxyscandebug(void *sender, int cargc, char **cargv); +int proxyscandosave(void *sender, int cargc, char **cargv); +int proxyscandospew(void *sender, int cargc, char **cargv); +int proxyscandoshowkill(void *sender, int cargc, char **cargv); +int proxyscandoscan(void *sender, int cargc, char **cargv); +int proxyscandoscanfile(void *sender, int cargc, char **cargv); +int proxyscandoaddscan(void *sender, int cargc, char **cargv); +int proxyscandodelscan(void *sender, int cargc, char **cargv); +int proxyscandoshowcommands(void *sender, int cargc, char **cargv); + int proxyscan_addscantype(int type, int port) { /* Check we have a spare scan slot */ @@ -124,11 +139,19 @@ int proxyscan_delscantype(int type, int port) { return 0; } +void ignorepipe(int signal_) { + signal(SIGPIPE, ignorepipe); /* HACK */ +} + void _init(void) { sstring *cfgstr; int ipbits[4]; + signal(SIGPIPE, ignorepipe); /* HACK */ + ps_start_ts = time(NULL); + ps_ready = 0; + ps_commands = NULL; ps_cache_ext = registernodeext("proxyscancache"); if( ps_cache_ext == -1 ) { @@ -149,7 +172,7 @@ void _init(void) { warningsent=0; ps_starttime=time(NULL); glinedhosts=0; - + scanspermin=0; lastscants=time(NULL); @@ -159,7 +182,7 @@ void _init(void) { freesstring(cfgstr); /* Max concurrent scans */ - cfgstr=getcopyconfigitem("proxyscan","maxscans","200",5); + cfgstr=getcopyconfigitem("proxyscan","maxscans","200",10); maxscans=strtol(cfgstr->content,NULL,10); freesstring(cfgstr); @@ -201,6 +224,8 @@ void _init(void) { /* Set up our nick on the network */ scheduleoneshot(time(NULL),®isterproxyscannick,NULL); + registerhook(HOOK_SERVER_END_OF_BURST, &proxyscan_onconnect); + registerhook(HOOK_NICK_NEWNICK,&proxyscan_newnick); registerhook(HOOK_CORE_STATSREQUEST,&proxyscanstats); @@ -218,8 +243,21 @@ void _init(void) { brokendb=0; } + ps_commands = newcommandtree(); + addcommandtotree(ps_commands, "showcommands", 0, 0, &proxyscandoshowcommands); + addcommandtotree(ps_commands, "status", 0, 0, &proxyscandostatus); + addcommandtotree(ps_commands, "listopen", 0, 0, &proxyscandolistopen); + addcommandtotree(ps_commands, "save", 0, 0, &proxyscandosave); + addcommandtotree(ps_commands, "spew", 0, 1, &proxyscandospew); + addcommandtotree(ps_commands, "showkill", 0, 1, &proxyscandoshowkill); + addcommandtotree(ps_commands, "scan", 0, 1, &proxyscandoscan); + addcommandtotree(ps_commands, "scanfile", 0, 1, &proxyscandoscanfile); + addcommandtotree(ps_commands, "addscan", 0, 1, &proxyscandoaddscan); + addcommandtotree(ps_commands, "delscan", 0, 1, &proxyscandodelscan); + /* Default scan types */ proxyscan_addscantype(STYPE_HTTP, 8080); + proxyscan_addscantype(STYPE_HTTP, 8118); proxyscan_addscantype(STYPE_HTTP, 80); proxyscan_addscantype(STYPE_HTTP, 6588); proxyscan_addscantype(STYPE_HTTP, 8000); @@ -230,6 +268,16 @@ void _init(void) { proxyscan_addscantype(STYPE_HTTP, 808); proxyscan_addscantype(STYPE_HTTP, 3332); proxyscan_addscantype(STYPE_HTTP, 2282); + + proxyscan_addscantype(STYPE_HTTP, 1644); + proxyscan_addscantype(STYPE_HTTP, 8081); + proxyscan_addscantype(STYPE_HTTP, 443); + proxyscan_addscantype(STYPE_HTTP, 1337); + proxyscan_addscantype(STYPE_HTTP, 8888); + proxyscan_addscantype(STYPE_HTTP, 8008); + proxyscan_addscantype(STYPE_HTTP, 6515); + proxyscan_addscantype(STYPE_HTTP, 27977); + proxyscan_addscantype(STYPE_SOCKS4, 559); proxyscan_addscantype(STYPE_SOCKS4, 1080); proxyscan_addscantype(STYPE_SOCKS5, 1080); @@ -252,11 +300,24 @@ void _init(void) { proxyscan_addscantype(STYPE_HTTP, 63809); proxyscan_addscantype(STYPE_HTTP, 63000); proxyscan_addscantype(STYPE_SOCKS4, 29992); - + proxyscan_addscantype(STYPE_DIRECT_IRC, 6666); + proxyscan_addscantype(STYPE_DIRECT_IRC, 6667); + proxyscan_addscantype(STYPE_DIRECT_IRC, 6668); + proxyscan_addscantype(STYPE_DIRECT_IRC, 6669); + proxyscan_addscantype(STYPE_DIRECT_IRC, 6670); + proxyscan_addscantype(STYPE_ROUTER, 3128); + proxyscan_addscantype(STYPE_SOCKS5, 27977); + /* Schedule saves */ schedulerecurring(time(NULL)+3600,0,3600,&dumpcachehosts,NULL); + + ps_logfile=fopen("logs/proxyscan.log","a"); - ps_logfile=fopen("proxyscan.log","a"); + if (connected) { + /* if we're already connected, assume we're just reloading module (i.e. have a completed burst) */ + ps_ready = 1; + startqueuedscans(); + } } void registerproxyscannick(void *arg) { @@ -292,21 +353,26 @@ void _fini(void) { deregisterlocaluser(proxyscannick,NULL); - releasenodeext(ps_cache_ext); - releasenodeext(ps_extscan_ext); + deregisterhook(HOOK_SERVER_END_OF_BURST, &proxyscan_onconnect); deregisterhook(HOOK_NICK_NEWNICK,&proxyscan_newnick); deregisterhook(HOOK_CORE_STATSREQUEST,&proxyscanstats); deleteschedule(NULL,&dumpcachehosts,NULL); - + + destroycommandtree(ps_commands); + /* Kill any scans in progress */ killallscans(); /* Dump the database - AFTER killallscans() which prunes it */ dumpcachehosts(NULL); + /* dump any cached hosts before deleting the extensions */ + releasenodeext(ps_cache_ext); + releasenodeext(ps_extscan_ext); + /* free() all our structures */ nsfreeall(POOL_PROXYSCAN); @@ -323,11 +389,9 @@ void _fini(void) { void proxyscanuserhandler(nick *target, int message, void **params) { nick *sender; - char *msg; - int i; - struct irc_in_addr sin; - unsigned char bits; - patricia_node_t *node; + Command *ps_command; + char *cargv[20]; + int cargc; switch(message) { case LU_KILLED: @@ -338,93 +402,27 @@ void proxyscanuserhandler(nick *target, int message, void **params) { case LU_PRIVMSG: case LU_SECUREMSG: sender=(nick *)params[0]; - msg=(char *)params[1]; if (IsOper(sender)) { - if (!ircd_strncmp(msg,"listopen",8)) { - proxyscandolistopen(proxyscannick,sender,time(NULL)-rescaninterval); - } - - if (!ircd_strncmp(msg,"status",6)) { - proxyscandostatus(sender); - } - - if (!ircd_strncmp(msg,"save",4)) { - dumpcachehosts(NULL); - sendnoticetouser(proxyscannick,sender,"Done."); - } - - if (!ircd_strncmp(msg,"debug",5)) { - proxyscandebug(sender); - } + cargc = splitline((char *)params[1], cargv, 20, 0); - if (!ircd_strncmp(msg,"spew ",5)) { - /* check our database for the ip supplied */ - unsigned long a,b,c,d; - if (4 != sscanf(&msg[5],"%lu.%lu.%lu.%lu",&a,&b,&c,&d)) { - sendnoticetouser(proxyscannick,sender,"Usage: spew x.x.x.x"); - } else { - /* check db */ - proxyscanspewip(proxyscannick,sender,a,b,c,d); - } - } + if ( cargc == 0 ) + return; - if (!ircd_strncmp(msg,"showkill ",9)) { - /* check our database for the id supplied */ - unsigned long a; - if (1 != sscanf(&msg[9],"%lu",&a)) { - sendnoticetouser(proxyscannick,sender,"Usage: showkill "); - } else { - /* check db */ - proxyscanshowkill(proxyscannick,sender,a); - } - } + ps_command = findcommandintree(ps_commands, cargv[0], 1); - if (!ircd_strncmp(msg,"scan ",5)) { - if (0 == ipmask_parse(&msg[5],&sin, &bits)) { - sendnoticetouser(proxyscannick,sender,"Usage: scan "); - } else { - sendnoticetouser(proxyscannick,sender,"Forcing scan of %s",IPtostr(sin)); - // * Just queue the scans directly here.. plonk them on the priority queue * / - node = refnode(iptree, &sin, bits); /* node leaks node here - should only allow to scan a nick? */ - for(i=0;i "); - } else { - sendnoticetouser(proxyscannick,sender,"Added scan type %u port %u",a,b); - proxyscan_addscantype(a,b); - scanall(a,b); - } + if ( ps_command->maxparams < (cargc-1) ) { + rejoinline(cargv[ps_command->maxparams], cargc - (ps_command->maxparams)); + cargc = (ps_command->maxparams) + 1; } - if (!ircd_strncmp(msg,"delscan ",8)) { - unsigned int a,b; - if (sscanf(msg+8,"%u %u",&a,&b) != 2) { - sendnoticetouser(proxyscannick,sender,"Usage: delscan "); - } else { - sendnoticetouser(proxyscannick,sender,"Delete scan type %u port %u",a,b); - proxyscan_delscantype(a,b); - } - } - - if ((!ircd_strncmp(msg,"help",4)) || (!ircd_strncmp(msg,"showcommands",12))) { - sendnoticetouser(proxyscannick,sender,"Proxyscan commands:"); - sendnoticetouser(proxyscannick,sender,"----------------------------------------------------------------------"); - sendnoticetouser(proxyscannick,sender,"help Shows this help"); - sendnoticetouser(proxyscannick,sender,"status Prints status information"); - sendnoticetouser(proxyscannick,sender,"listopen Shows open proxies found recently"); - sendnoticetouser(proxyscannick,sender,"save Saves the clean host database"); - sendnoticetouser(proxyscannick,sender,"scan Force scan of the supplied IP"); - sendnoticetouser(proxyscannick,sender,"spew Find in our list of open proxies"); - sendnoticetouser(proxyscannick,sender,"showkill Shows details of a kill or gline made by the service"); - } + (ps_command->handler)((void *)sender, cargc - 1, &(cargv[1])); + break; } default: @@ -502,10 +500,11 @@ void startscan(patricia_node_t *node, int type, int port, int class) { sp->totalbytesread=0; memset(sp->readbuf, '\0', PSCAN_READBUFSIZE); - sp->fd=createconnectsocket(irc_in_addr_v4_to_int(&((patricia_node_t *)sp->node)->prefix->sin),sp->port); + sp->fd=createconnectsocket(&((patricia_node_t *)sp->node)->prefix->sin,sp->port); sp->state=SSTATE_CONNECTING; if (sp->fd<0) { /* Couldn't set up the socket? */ + derefnode(iptree,sp->node); freescan(sp); return; } @@ -526,6 +525,8 @@ void killsock(scan *sp, int outcome) { int i; cachehost *chp; foundproxy *fpp; + time_t now; + char reason[200]; scansdone++; scansbyclass[sp->class]++; @@ -570,13 +571,24 @@ void killsock(scan *sp, int outcome) { fpp->next=chp->proxies; chp->proxies=fpp; } - - if (!chp->glineid) { + + now=time(NULL); + /* the purpose of this lastgline stuff is to stop gline spam from one scan */ + if (!chp->glineid || (now>=chp->lastgline+SCANTIMEOUT)) { + char buf[512]; + struct irc_in_addr *ip; + + chp->lastgline=now; glinedhosts++; - loggline(chp, sp->node); - irc_send("%s GL * +*@%s 1800 :Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d", - mynumeric->content,IPtostr(((patricia_node_t *)sp->node)->prefix->sin),chp->glineid); - Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",IPtostr(((patricia_node_t *)sp->node)->prefix->sin)); + + loggline(chp, sp->node); + ip = &(((patricia_node_t *)sp->node)->prefix->sin); + snprintf(reason, sizeof(reason), "Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d", chp->glineid); + glinebyip("*", ip, 128, 43200, reason, GLINE_IGNORE_TRUST, "proxyscan"); + Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",IPtostr(*ip)); + + snprintf(buf, sizeof(buf), "proxy-gline %lu %s %s %hu %s", time(NULL), IPtostr(*ip), scantostr(sp->type), sp->port, "irc.quakenet.org"); + triggerhook(HOOK_SHADOW_SERVER, (void *)buf); } else { loggline(chp, sp->node); /* Update log only */ } @@ -590,6 +602,8 @@ void killsock(scan *sp, int outcome) { } } + /* deref prefix (referenced in queuescan) */ + derefnode(iptree,sp->node); freescan(sp); /* kick the queue.. */ @@ -644,7 +658,7 @@ void handlescansock(int fd, short events) { switch(sp->type) { case STYPE_HTTP: - sprintf(buf,"CONNECT %s:%d HTTP/1.0\r\n\r\n",myipstr->content,listenport); + sprintf(buf,"CONNECT %s:%d HTTP/1.0\r\n\r\n\r\n",myipstr->content,listenport); if ((write(fd,buf,strlen(buf)))bytesread+=res; sp->totalbytesread+=res; - for (i=0;ibytesread - MAGICSTRINGLENGTH;i++) { - if (!strncmp(sp->readbuf+i, MAGICSTRING, MAGICSTRINGLENGTH)) { - /* Found the magic string */ - /* If the offset is 0, this means it was the first thing we got from the socket, - * so it's an actual IRCD (sheesh). Note that when the buffer is full and moved, - * the thing moved to offset 0 would previously have been tested as offset - * PSCAN_READBUFSIZE/2. - * - * Skip this checking for STYPE_DIRECT scans, which are used to detect trojans setting - * up portforwards (which will therefore show up as ircds, we rely on the port being - * strange enough to avoid false positives */ - if (i==0 && (sp->type != STYPE_DIRECT)) { - killsock(sp, SOUTCOME_CLOSED); - return; + + { + char *magicstring; + int magicstringlength; + + if(sp->type == STYPE_DIRECT_IRC) { + magicstring = MAGICIRCSTRING; + magicstringlength = MAGICIRCSTRINGLENGTH; + } else if(sp->type == STYPE_ROUTER) { + magicstring = MAGICROUTERSTRING; + magicstringlength = MAGICROUTERSTRINGLENGTH; + } else { + magicstring = MAGICSTRING; + magicstringlength = MAGICSTRINGLENGTH; + if(sp->totalbytesread - res == 0) { + buf[0] = '\n'; + write(fd,buf,1); } + } + + for (i=0;ibytesread - magicstringlength;i++) { + if (!strncmp(sp->readbuf+i, magicstring, magicstringlength)) { + /* Found the magic string */ + /* If the offset is 0, this means it was the first thing we got from the socket, + * so it's an actual IRCD (sheesh). Note that when the buffer is full and moved, + * the thing moved to offset 0 would previously have been tested as offset + * PSCAN_READBUFSIZE/2. + * + * Skip this checking for STYPE_DIRECT scans, which are used to detect trojans setting + * up portforwards (which will therefore show up as ircds, we rely on the port being + * strange enough to avoid false positives */ + if (i==0 && (sp->type != STYPE_DIRECT)) { + killsock(sp, SOUTCOME_CLOSED); + return; + } - killsock(sp, SOUTCOME_OPEN); - return; + killsock(sp, SOUTCOME_OPEN); + return; + } } } @@ -833,7 +888,8 @@ int pscansort(const void *a, const void *b) { return thescans[ra].hits - thescans[rb].hits; } -void proxyscandostatus(nick *np) { +int proxyscandostatus(void *sender, int cargc, char **cargv) { + nick *np = (nick *) sender; int i; int totaldetects=0; int ord[PSCAN_MAXSCANS]; @@ -870,16 +926,16 @@ void proxyscandostatus(nick *np) { scantostr(thescans[ord[i]].type), thescans[ord[i]].port, thescans[ord[i]].hits, ((float)thescans[ord[i]].hits*100)/totaldetects); sendnoticetouser(proxyscannick,np,"End of list."); + return CMD_OK; } -void proxyscandebug(nick *np) { +int proxyscandebug(void *sender, int cargc, char **cargv) { /* Dump all scans.. */ int i; int activescansfound=0; int totalscansfound=0; scan *sp; - patricia_node_t *node; - cachehost *chp; + nick *np = (nick *)sender; sendnoticetouser(proxyscannick,np,"Active scans : %d",activescans); @@ -894,13 +950,222 @@ void proxyscandebug(nick *np) { } } - PATRICIA_WALK (iptree->head, node) { - if ( node->exts[ps_cache_ext] ) { - chp = (cachehost *) node->exts[ps_cache_ext]; - if (chp) - sendnoticetouser(proxyscannick,np,"node: %s , chp: %p", IPtostr(((patricia_node_t *)node)->prefix->sin), chp); + sendnoticetouser(proxyscannick,np,"Total %d scans actually found (%d active)",totalscansfound,activescansfound); + return CMD_OK; +} + +void proxyscan_onconnect(int hooknum, void *arg) { + ps_ready = 1; + + /* kick the queue.. */ + startqueuedscans(); +} + +int proxyscandosave(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + + sendnoticetouser(proxyscannick,np,"Saving cached hosts..."); + dumpcachehosts(NULL); + sendnoticetouser(proxyscannick,np,"Done."); + return CMD_OK; +} + +int proxyscandospew(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + + if(cargc < 1) + return CMD_USAGE; + + /* check our database for the ip supplied */ + unsigned long a,b,c,d; + if (4 != sscanf(cargv[0],"%lu.%lu.%lu.%lu",&a,&b,&c,&d)) { + sendnoticetouser(proxyscannick,np,"Usage: spew x.x.x.x"); + } else { + /* check db */ + proxyscanspewip(proxyscannick,np,a,b,c,d); + } + return CMD_OK; +} + +int proxyscandoshowkill(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + + if(cargc < 1) + return CMD_USAGE; + + /* check our database for the id supplied */ + unsigned long a; + if (1 != sscanf(cargv[0],"%lu",&a)) { + sendnoticetouser(proxyscannick,np,"Usage: showkill "); + } else { + /* check db */ + proxyscanshowkill(proxyscannick,np,a); + } + return CMD_OK; +} + +void startnickscan(nick *np) { + time_t t = time(NULL); + int i; + for(i=0;iipnode,thescans[i].type,thescans[i].port,SCLASS_NORMAL,t); + } +} + +int proxyscandoscan(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + patricia_node_t *node; + struct irc_in_addr sin; + unsigned char bits; + int i; + + if(cargc < 1) + return CMD_USAGE; + + if (0 == ipmask_parse(cargv[0],&sin, &bits)) { + sendnoticetouser(proxyscannick,np,"Usage: scan "); + } else { + if (bits != 128 || !irc_in_addr_is_ipv4(&sin) || irc_in_addr_is_loopback(&sin)) { + sendnoticetouser(proxyscannick,np,"You may only scan single IPv4 IP's"); + return CMD_OK; + } + if (bits != 128 || irc_in_addr_is_loopback(&sin)) { + sendnoticetouser(proxyscannick,np,"You may only scan single IP's"); + return CMD_OK; + } + + time_t t; + sendnoticetouser(proxyscannick,np,"Forcing scan of %s",IPtostr(sin)); + // * Just queue the scans directly here.. plonk them on the priority queue * / + node = refnode(iptree, &sin, bits); /* node leaks node here - should only allow to scan a nick? */ + t = time(NULL); + for(i=0;i maxno) + maxno = thescans[i].type; + + tscantypes = malloc(sizeof(int) * maxno); + for(i=0;i "); + } else { + sendnoticetouser(proxyscannick,np,"Added scan type %u port %u",a,b); + proxyscan_addscantype(a,b); + scanall(a,b); + } + return CMD_OK; +} + +int proxyscandodelscan(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + + if(cargc < 1) + return CMD_USAGE; + + unsigned int a,b; + if (sscanf(cargv[0],"%u %u",&a,&b) != 2) { + sendnoticetouser(proxyscannick,np,"Usage: delscan "); + } else { + sendnoticetouser(proxyscannick,np,"Delete scan type %u port %u",a,b); + proxyscan_delscantype(a,b); + } + return CMD_OK; +} + +int proxyscandoshowcommands(void *sender, int cargc, char **cargv) { + nick *np = (nick *)sender; + Command *cmdlist[100]; + int i,n; + + n=getcommandlist(ps_commands,cmdlist,100); + + sendnoticetouser(proxyscannick,np,"The following commands are registered at present:"); + for(i=0;icommand->content); + } + sendnoticetouser(proxyscannick,np,"End of list."); + return CMD_OK; }