]> jfr.im git - irc/quakenet/newserv.git/blame - proxyscan/proxyscan.c
Merge.
[irc/quakenet/newserv.git] / proxyscan / proxyscan.c
CommitLineData
c86edd1d
Q
1
2#include "proxyscan.h"
3
4#include <sys/poll.h>
5#include <sys/types.h>
6#include <sys/socket.h>
7#include <netdb.h>
8#include "../core/error.h"
9#include "../core/events.h"
10#include <stdlib.h>
11#include <stdio.h>
12#include <errno.h>
13#include "../nick/nick.h"
14#include "../core/hooks.h"
15#include "../lib/sstring.h"
16#include "../irc/irc_config.h"
17#include "../localuser/localuser.h"
18#include "../core/config.h"
19#include <unistd.h>
20#include "../core/schedule.h"
21#include <string.h>
22#include "../irc/irc.h"
23#include "../lib/irc_string.h"
cfd3214b
CP
24#include "../lib/version.h"
25#include "../channel/channel.h"
26#include "../localuser/localuserchannel.h"
818e3d5f 27#include "../core/nsmalloc.h"
557c8cb2 28#include "../lib/irc_ipv6.h"
cfd3214b
CP
29
30MODULE_VERSION("")
c86edd1d
Q
31
32#define SCANTIMEOUT 60
33
34#define SCANHOSTHASHSIZE 1000
35#define SCANHASHSIZE 400
36
37/* It's unlikely you'll get 100k of preamble before a connect... */
38#define READ_SANITY_LIMIT 102400
39
40scan *scantable[SCANHASHSIZE];
41
7ab80d0c
P
42CommandTree *ps_commands;
43
c86edd1d
Q
44int listenfd;
45int activescans;
46int maxscans;
47int queuedhosts;
48int scansdone;
49int rescaninterval;
50int warningsent;
51int glinedhosts;
2220c058 52time_t ps_starttime;
557c8cb2
P
53int ps_cache_ext;
54int ps_extscan_ext;
7ab80d0c 55int ps_ready;
c86edd1d
Q
56
57int numscans; /* number of scan types currently valid */
58scantype thescans[PSCAN_MAXSCANS];
59
60unsigned int hitsbyclass[10];
61unsigned int scansbyclass[10];
62
63unsigned int myip;
64sstring *myipstr;
65unsigned short listenport;
66int brokendb;
67
68unsigned int ps_mailip;
69unsigned int ps_mailport;
70sstring *ps_mailname;
71
92f1d9e3
D
72unsigned long scanspermin;
73unsigned long tempscanspermin=0;
74unsigned long lastscants=0;
75
761a4596
P
76unsigned int ps_start_ts=0;
77
c86edd1d
Q
78nick *proxyscannick;
79
80FILE *ps_logfile;
81
82/* Local functions */
83void handlescansock(int fd, short events);
84void timeoutscansock(void *arg);
85void proxyscan_newnick(int hooknum, void *arg);
86void proxyscan_lostnick(int hooknum, void *arg);
7ab80d0c 87void proxyscan_onconnect(int hooknum, void *arg);
c86edd1d
Q
88void proxyscanuserhandler(nick *target, int message, void **params);
89void registerproxyscannick();
90void killsock(scan *sp, int outcome);
91void killallscans();
92void proxyscanstats(int hooknum, void *arg);
93void sendlagwarning();
c86edd1d
Q
94void proxyscan_newip(nick *np, unsigned long ip);
95int proxyscan_addscantype(int type, int port);
96int proxyscan_delscantype(int type, int port);
97
7ab80d0c
P
98int proxyscandostatus(void *sender, int cargc, char **cargv);
99int proxyscandebug(void *sender, int cargc, char **cargv);
100int proxyscandosave(void *sender, int cargc, char **cargv);
101int proxyscandospew(void *sender, int cargc, char **cargv);
102int proxyscandoshowkill(void *sender, int cargc, char **cargv);
103int proxyscandoscan(void *sender, int cargc, char **cargv);
104int proxyscandoaddscan(void *sender, int cargc, char **cargv);
105int proxyscandodelscan(void *sender, int cargc, char **cargv);
106int proxyscandoshowcommands(void *sender, int cargc, char **cargv);
107
c86edd1d
Q
108int proxyscan_addscantype(int type, int port) {
109 /* Check we have a spare scan slot */
110
111 if (numscans>=PSCAN_MAXSCANS)
112 return 1;
113
114 thescans[numscans].type=type;
115 thescans[numscans].port=port;
116 thescans[numscans].hits=0;
117
118 numscans++;
119
120 return 0;
121}
122
123int proxyscan_delscantype(int type, int port) {
124 int i;
125
126 for (i=0;i<numscans;i++)
127 if (thescans[i].type==type && thescans[i].port==port)
128 break;
129
130 if (i>=numscans)
131 return 1;
132
133 memmove(thescans+i, thescans+(i+1), (PSCAN_MAXSCANS-(i+1)) * sizeof(scantype));
134 numscans--;
135
136 return 0;
137}
138
139void _init(void) {
140 sstring *cfgstr;
141 int ipbits[4];
142
761a4596 143 ps_start_ts = time(NULL);
7ab80d0c
P
144 ps_ready = 0;
145 ps_commands = NULL;
761a4596 146
557c8cb2 147 ps_cache_ext = registernodeext("proxyscancache");
a8ba1373
P
148 if( ps_cache_ext == -1 ) {
149 Error("proxyscan",ERR_INFO,"failed to reg node ext");
150 return;
557c8cb2
P
151 }
152 ps_extscan_ext = registernodeext("proxyscanextscan");
a8ba1373
P
153 if ( ps_extscan_ext == -1) {
154 Error("proxyscan",ERR_INFO,"failed to reg node ext");
155 return;
557c8cb2 156 }
a8ba1373 157
c86edd1d
Q
158 memset(scantable,0,sizeof(scantable));
159 maxscans=200;
160 activescans=0;
161 queuedhosts=0;
162 scansdone=0;
163 warningsent=0;
2220c058 164 ps_starttime=time(NULL);
c86edd1d 165 glinedhosts=0;
7ab80d0c 166
92f1d9e3
D
167 scanspermin=0;
168 lastscants=time(NULL);
169
c86edd1d
Q
170 /* Listen port */
171 cfgstr=getcopyconfigitem("proxyscan","port","9999",6);
172 listenport=strtol(cfgstr->content,NULL,10);
173 freesstring(cfgstr);
174
175 /* Max concurrent scans */
5de2923d 176 cfgstr=getcopyconfigitem("proxyscan","maxscans","200",10);
c86edd1d
Q
177 maxscans=strtol(cfgstr->content,NULL,10);
178 freesstring(cfgstr);
179
180 /* Clean host timeout */
181 cfgstr=getcopyconfigitem("proxyscan","rescaninterval","3600",7);
182 rescaninterval=strtol(cfgstr->content,NULL,10);
183 cachehostinit(rescaninterval);
184 freesstring(cfgstr);
185
186 /* this default will NOT work well */
187 myipstr=getcopyconfigitem("proxyscan","ip","127.0.0.1",16);
188
189 sscanf(myipstr->content,"%d.%d.%d.%d",&ipbits[0],&ipbits[1],&ipbits[2],&ipbits[3]);
190
191 myip=((ipbits[0]&0xFF)<<24)+((ipbits[1]&0xFF)<<16)+
192 ((ipbits[2]&0xFF)<<8)+(ipbits[3]&0xFF);
193
f94f9cec 194#if defined(PROXYSCAN_MAIL)
c86edd1d
Q
195 /* Mailer host */
196 cfgstr=getcopyconfigitem("proxyscan","mailerip","",16);
197
c86edd1d
Q
198 psm_mailerfd=-1;
199 if (cfgstr) {
200 sscanf(cfgstr->content,"%d.%d.%d.%d",&ipbits[0],&ipbits[1],&ipbits[2],&ipbits[3]);
201 ps_mailip = ((ipbits[0]&0xFF)<<24)+((ipbits[1]&0xFF)<<16)+
202 ((ipbits[2]&0xFF)<<8)+(ipbits[3]&0xFF);
203 ps_mailport=25;
204 freesstring(cfgstr);
205
206 ps_mailname=getcopyconfigitem("proxyscan","mailname","some.mail.server",HOSTLEN);
c9db668b 207 Error("proxyscan",ERR_INFO,"Proxyscan mailer enabled; mailing to %s as %s.",IPlongtostr(ps_mailip),ps_mailname->content);
c86edd1d
Q
208 } else {
209 ps_mailport=0;
210 ps_mailname=NULL;
211 }
212#endif
213
214 proxyscannick=NULL;
215 /* Set up our nick on the network */
216 scheduleoneshot(time(NULL),&registerproxyscannick,NULL);
217
7ab80d0c
P
218 registerhook(HOOK_SERVER_END_OF_BURST, &proxyscan_onconnect);
219
c86edd1d
Q
220 registerhook(HOOK_NICK_NEWNICK,&proxyscan_newnick);
221
222 registerhook(HOOK_CORE_STATSREQUEST,&proxyscanstats);
223
224 /* Read in the clean hosts */
225 loadcachehosts();
226
557c8cb2
P
227 /* Read in any custom ports to scan */
228 loadextrascans();
229
c86edd1d
Q
230 /* Set up the database */
231 if ((proxyscandbinit())!=0) {
232 brokendb=1;
233 } else {
234 brokendb=0;
235 }
236
7ab80d0c
P
237 ps_commands = newcommandtree();
238 addcommandtotree(ps_commands, "showcommands", 0, 0, &proxyscandoshowcommands);
239 addcommandtotree(ps_commands, "status", 0, 0, &proxyscandostatus);
240 addcommandtotree(ps_commands, "listopen", 0, 0, &proxyscandolistopen);
241 addcommandtotree(ps_commands, "save", 0, 0, &proxyscandosave);
5de2923d
CP
242 addcommandtotree(ps_commands, "spew", 0, 1, &proxyscandospew);
243 addcommandtotree(ps_commands, "showkill", 0, 1, &proxyscandoshowkill);
244 addcommandtotree(ps_commands, "scan", 0, 1, &proxyscandoscan);
245 addcommandtotree(ps_commands, "addscan", 0, 1, &proxyscandoaddscan);
246 addcommandtotree(ps_commands, "delscan", 0, 1, &proxyscandodelscan);
7ab80d0c 247
c86edd1d
Q
248 /* Default scan types */
249 proxyscan_addscantype(STYPE_HTTP, 8080);
7a91c1d0 250 proxyscan_addscantype(STYPE_HTTP, 8118);
c86edd1d
Q
251 proxyscan_addscantype(STYPE_HTTP, 80);
252 proxyscan_addscantype(STYPE_HTTP, 6588);
253 proxyscan_addscantype(STYPE_HTTP, 8000);
254 proxyscan_addscantype(STYPE_HTTP, 3128);
255 proxyscan_addscantype(STYPE_HTTP, 3802);
256 proxyscan_addscantype(STYPE_HTTP, 5490);
257 proxyscan_addscantype(STYPE_HTTP, 7441);
258 proxyscan_addscantype(STYPE_HTTP, 808);
259 proxyscan_addscantype(STYPE_HTTP, 3332);
260 proxyscan_addscantype(STYPE_HTTP, 2282);
0a85c6ba 261 proxyscan_addscantype(STYPE_SOCKS4, 559);
c86edd1d
Q
262 proxyscan_addscantype(STYPE_SOCKS4, 1080);
263 proxyscan_addscantype(STYPE_SOCKS5, 1080);
264 proxyscan_addscantype(STYPE_SOCKS4, 1075);
265 proxyscan_addscantype(STYPE_SOCKS5, 1075);
266 proxyscan_addscantype(STYPE_SOCKS4, 2280);
267 proxyscan_addscantype(STYPE_SOCKS5, 2280);
268 proxyscan_addscantype(STYPE_SOCKS4, 1180);
269 proxyscan_addscantype(STYPE_SOCKS5, 1180);
0a85c6ba
P
270 proxyscan_addscantype(STYPE_SOCKS4, 9999);
271 proxyscan_addscantype(STYPE_SOCKS5, 9999);
c86edd1d
Q
272 proxyscan_addscantype(STYPE_WINGATE, 23);
273 proxyscan_addscantype(STYPE_CISCO, 23);
274 proxyscan_addscantype(STYPE_WINGATE, 1181);
275 proxyscan_addscantype(STYPE_SOCKS5, 1978);
276 proxyscan_addscantype(STYPE_SOCKS5, 1029);
277 proxyscan_addscantype(STYPE_SOCKS5, 3801);
278 proxyscan_addscantype(STYPE_SOCKS5, 3331);
279 proxyscan_addscantype(STYPE_HTTP, 65506);
280 proxyscan_addscantype(STYPE_HTTP, 63809);
905c2ba2 281 proxyscan_addscantype(STYPE_HTTP, 63000);
92f1d9e3 282 proxyscan_addscantype(STYPE_SOCKS4, 29992);
468b83b2 283 proxyscan_addscantype(STYPE_DIRECT_IRC, 6666);
c7be40f8
CP
284 proxyscan_addscantype(STYPE_DIRECT_IRC, 6667);
285 proxyscan_addscantype(STYPE_DIRECT_IRC, 6668);
286 proxyscan_addscantype(STYPE_DIRECT_IRC, 6669);
287 proxyscan_addscantype(STYPE_DIRECT_IRC, 6670);
e95140be 288 proxyscan_addscantype(STYPE_ROUTER, 3128);
32f6f393 289 proxyscan_addscantype(STYPE_SOCKS5, 27977);
7ab80d0c 290
c86edd1d
Q
291 /* Schedule saves */
292 schedulerecurring(time(NULL)+3600,0,3600,&dumpcachehosts,NULL);
7ab80d0c
P
293
294 ps_logfile=fopen("logs/proxyscan.log","a");
c86edd1d 295
7ab80d0c
P
296 if (connected) {
297 /* if we're already connected, assume we're just reloading module (i.e. have a completed burst) */
298 ps_ready = 1;
299 startqueuedscans();
300 }
c86edd1d
Q
301}
302
303void registerproxyscannick(void *arg) {
304 sstring *psnick,*psuser,*pshost,*psrealname;
305 /* Set up our nick on the network */
cfd3214b 306 channel *cp;
c86edd1d
Q
307
308 psnick=getcopyconfigitem("proxyscan","nick","P",NICKLEN);
309 psuser=getcopyconfigitem("proxyscan","user","proxyscan",USERLEN);
310 pshost=getcopyconfigitem("proxyscan","host","some.host",HOSTLEN);
311 psrealname=getcopyconfigitem("proxyscan","realname","Proxyscan",REALLEN);
312
313 proxyscannick=registerlocaluser(psnick->content,psuser->content,pshost->content,
314 psrealname->content,
315 NULL,UMODE_OPER|UMODE_SERVICE|UMODE_DEAF,
316 &proxyscanuserhandler);
317
318 freesstring(psnick);
319 freesstring(psuser);
320 freesstring(pshost);
321 freesstring(psrealname);
cfd3214b
CP
322
323 cp=findchannel("#twilightzone");
324 if (!cp) {
325 localcreatechannel(proxyscannick,"#twilightzone");
326 } else {
327 localjoinchannel(proxyscannick,cp);
328 localgetops(proxyscannick,cp);
329 }
c86edd1d
Q
330}
331
332void _fini(void) {
333
334 deregisterlocaluser(proxyscannick,NULL);
557c8cb2 335
7ab80d0c 336 deregisterhook(HOOK_SERVER_END_OF_BURST, &proxyscan_onconnect);
c86edd1d
Q
337
338 deregisterhook(HOOK_NICK_NEWNICK,&proxyscan_newnick);
339
340 deregisterhook(HOOK_CORE_STATSREQUEST,&proxyscanstats);
341
342 deleteschedule(NULL,&dumpcachehosts,NULL);
7ab80d0c
P
343
344 destroycommandtree(ps_commands);
345
c86edd1d
Q
346 /* Kill any scans in progress */
347 killallscans();
348
349 /* Dump the database - AFTER killallscans() which prunes it */
350 dumpcachehosts(NULL);
351
7ab80d0c
P
352 /* dump any cached hosts before deleting the extensions */
353 releasenodeext(ps_cache_ext);
354 releasenodeext(ps_extscan_ext);
355
c86edd1d 356 /* free() all our structures */
818e3d5f 357 nsfreeall(POOL_PROXYSCAN);
c86edd1d 358
6e228f06 359 freesstring(myipstr);
c86edd1d
Q
360 freesstring(ps_mailname);
361#if defined(PROXYSCAN_MAIL)
362 if (psm_mailerfd!=-1)
363 deregisterhandler(psm_mailerfd,1);
364#endif
365
366 if (ps_logfile)
367 fclose(ps_logfile);
368}
369
370void proxyscanuserhandler(nick *target, int message, void **params) {
371 nick *sender;
7ab80d0c
P
372 Command *ps_command;
373 char *cargv[20];
374 int cargc;
c86edd1d
Q
375
376 switch(message) {
377 case LU_KILLED:
378 scheduleoneshot(time(NULL)+1,&registerproxyscannick,NULL);
379 proxyscannick=NULL;
380 break;
381
382 case LU_PRIVMSG:
383 case LU_SECUREMSG:
384 sender=(nick *)params[0];
c86edd1d
Q
385
386 if (IsOper(sender)) {
7ab80d0c 387 cargc = splitline((char *)params[1], cargv, 20, 0);
7d228b1d 388
7ab80d0c
P
389 if ( cargc == 0 )
390 return;
7d228b1d 391
7ab80d0c 392 ps_command = findcommandintree(ps_commands, cargv[0], 1);
7d228b1d 393
7ab80d0c
P
394 if ( !ps_command ) {
395 sendnoticetouser(proxyscannick,sender, "Unknown command.");
396 return;
c86edd1d
Q
397 }
398
7ab80d0c
P
399 if ( ps_command->maxparams < (cargc-1) ) {
400 rejoinline(cargv[ps_command->maxparams], cargc - (ps_command->maxparams));
401 cargc = (ps_command->maxparams) + 1;
c86edd1d
Q
402 }
403
7ab80d0c
P
404 (ps_command->handler)((void *)sender, cargc - 1, &(cargv[1]));
405 break;
c86edd1d
Q
406 }
407
408 default:
409 break;
410 }
411}
412
413void addscantohash(scan *sp) {
414 int hash;
415 hash=(sp->fd)%SCANHASHSIZE;
416
417 sp->next=scantable[hash];
418 scantable[hash]=sp;
419
420 activescans++;
421}
422
423void delscanfromhash(scan *sp) {
424 int hash;
425 scan **sh;
426
427 hash=(sp->fd)%SCANHASHSIZE;
428
429 for (sh=&(scantable[hash]);*sh;sh=&((*sh)->next)) {
430 if (*sh==sp) {
431 (*sh)=sp->next;
432 break;
433 }
434 }
435
436 activescans--;
437}
438
439scan *findscan(int fd) {
440 int hash;
441 scan *sp;
442
443 hash=fd%SCANHASHSIZE;
444
445 for (sp=scantable[hash];sp;sp=sp->next)
446 if (sp->fd==fd)
447 return sp;
448
449 return NULL;
450}
451
557c8cb2 452void startscan(patricia_node_t *node, int type, int port, int class) {
c86edd1d 453 scan *sp;
92f1d9e3
D
454 float scantmp;
455
456 if (scansdone>maxscans)
457 {
458 /* ignore the first maxscans as this will skew our scans per second! */
459 tempscanspermin++;
460 if ((lastscants+60) <= time(NULL))
461 {
462 /* ok, at least 60 seconds has passed, calculate the scans per minute figure */
463 scantmp = time(NULL) - lastscants;
464 scantmp = tempscanspermin / scantmp;
465 scantmp = (scantmp * 60);
466 scanspermin = scantmp;
467 lastscants = time(NULL);
468 tempscanspermin = 0;
469 }
470 }
c86edd1d
Q
471
472 sp=getscan();
473
474 sp->outcome=SOUTCOME_INPROGRESS;
475 sp->port=port;
557c8cb2 476 sp->node=node;
c86edd1d
Q
477 sp->type=type;
478 sp->class=class;
479 sp->bytesread=0;
480 sp->totalbytesread=0;
481 memset(sp->readbuf, '\0', PSCAN_READBUFSIZE);
482
3e986f5e 483 sp->fd=createconnectsocket(&((patricia_node_t *)sp->node)->prefix->sin,sp->port);
c86edd1d
Q
484 sp->state=SSTATE_CONNECTING;
485 if (sp->fd<0) {
486 /* Couldn't set up the socket? */
919fa66b 487 derefnode(iptree,sp->node);
c86edd1d
Q
488 freescan(sp);
489 return;
490 }
491 /* Wait until it is writeable */
492 registerhandler(sp->fd,POLLERR|POLLHUP|POLLOUT,&handlescansock);
493 /* And set a timeout */
494 sp->sch=scheduleoneshot(time(NULL)+SCANTIMEOUT,&timeoutscansock,(void *)sp);
495 addscantohash(sp);
496}
497
498void timeoutscansock(void *arg) {
499 scan *sp=(scan *)arg;
500
501 killsock(sp, SOUTCOME_CLOSED);
502}
503
504void killsock(scan *sp, int outcome) {
505 int i;
506 cachehost *chp;
507 foundproxy *fpp;
bef1f120 508 time_t now;
c86edd1d
Q
509
510 scansdone++;
511 scansbyclass[sp->class]++;
512
513 /* Remove the socket from the schedule/event lists */
514 deregisterhandler(sp->fd,1); /* this will close the fd for us */
515 deleteschedule(sp->sch,&timeoutscansock,(void *)sp);
516
517 sp->outcome=outcome;
518 delscanfromhash(sp);
519
520 /* See if we need to queue another scan.. */
521 if (sp->outcome==SOUTCOME_CLOSED &&
522 ((sp->class==SCLASS_CHECK) ||
523 (sp->class==SCLASS_NORMAL && (sp->state==SSTATE_SENTREQUEST || sp->state==SSTATE_GOTRESPONSE))))
557c8cb2 524 queuescan(sp->node, sp->type, sp->port, SCLASS_PASS2, time(NULL)+300);
c86edd1d
Q
525
526 if (sp->outcome==SOUTCOME_CLOSED && sp->class==SCLASS_PASS2)
557c8cb2 527 queuescan(sp->node, sp->type, sp->port, SCLASS_PASS3, time(NULL)+300);
c86edd1d
Q
528
529 if (sp->outcome==SOUTCOME_CLOSED && sp->class==SCLASS_PASS3)
557c8cb2 530 queuescan(sp->node, sp->type, sp->port, SCLASS_PASS4, time(NULL)+300);
c86edd1d
Q
531
532 if (sp->outcome==SOUTCOME_OPEN) {
533 hitsbyclass[sp->class]++;
534
535 /* Lets try and get the cache record. If there isn't one, make a new one. */
557c8cb2
P
536 if (!(chp=findcachehost(sp->node))) {
537 chp=addcleanhost(time(NULL));
538 patricia_ref_prefix(sp->node->prefix);
a8ba1373 539 sp->node->exts[ps_cache_ext] = chp;
557c8cb2 540 }
c86edd1d
Q
541 /* Stick it on the cache's list of proxies, if necessary */
542 for (fpp=chp->proxies;fpp;fpp=fpp->next)
543 if (fpp->type==sp->type && fpp->port==sp->port)
544 break;
545
546 if (!fpp) {
547 fpp=getfoundproxy();
548 fpp->type=sp->type;
549 fpp->port=sp->port;
550 fpp->next=chp->proxies;
551 chp->proxies=fpp;
552 }
bef1f120
CP
553
554 now=time(NULL);
555 /* the purpose of this lastgline stuff is to stop gline spam from one scan */
556 if (!chp->glineid || (now>=chp->lastgline+SCANTIMEOUT)) {
05dc4fd5
CP
557 char buf[512];
558 const char *ip;
559
bef1f120 560 chp->lastgline=now;
c86edd1d 561 glinedhosts++;
05dc4fd5 562
bef1f120 563 loggline(chp, sp->node);
05dc4fd5 564 ip = IPtostr(((patricia_node_t *)sp->node)->prefix->sin);
68e41288 565 irc_send("%s GL * +*@%s 1800 %jd :Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d",
05dc4fd5
CP
566 mynumeric->content,ip,(intmax_t)getnettime(), chp->glineid);
567 Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",ip);
568
569 snprintf(buf, sizeof(buf), "proxy-gline %lu %s %s %hu %s", time(NULL), ip, scantostr(sp->type), sp->port, "irc.quakenet.org");
570 triggerhook(HOOK_SHADOW_SERVER, (void *)buf);
c86edd1d 571 } else {
557c8cb2 572 loggline(chp, sp->node); /* Update log only */
c86edd1d
Q
573 }
574
575 /* Update counter */
576 for(i=0;i<numscans;i++) {
577 if (thescans[i].type==sp->type && thescans[i].port==sp->port) {
578 thescans[i].hits++;
579 break;
580 }
581 }
582 }
583
9ae689d8
P
584 /* deref prefix (referenced in queuescan) */
585 derefnode(iptree,sp->node);
c86edd1d
Q
586 freescan(sp);
587
588 /* kick the queue.. */
589 startqueuedscans();
590}
591
592void handlescansock(int fd, short events) {
593 scan *sp;
594 char buf[512];
595 int res;
596 int i;
597 unsigned long netip;
598 unsigned short netport;
599
600 if ((sp=findscan(fd))==NULL) {
601 /* Not found; return and hope it goes away */
602 Error("proxyscan",ERR_ERROR,"Unexpected message from fd %d",fd);
603 return;
604 }
605
606 /* It woke up, delete the alarm call.. */
607 deleteschedule(sp->sch,&timeoutscansock,(void *)sp);
608
609 if (events & (POLLERR|POLLHUP)) {
610 /* Some kind of error; give up on this socket */
611 if (sp->state==SSTATE_GOTRESPONSE) {
612 /* If the error occured while we were waiting for a response, we might have
613 * received the "OPEN PROXY!" message and the EOF at the same time, so continue
614 * processing */
615/* Error("proxyscan",ERR_DEBUG,"Got error in GOTRESPONSE state for %s, continuing.",IPtostr(sp->host->IP)); */
616 } else {
617 killsock(sp, SOUTCOME_CLOSED);
618 return;
619 }
620 }
621
622 /* Otherwise, we got what we wanted.. */
623
624 switch(sp->state) {
625 case SSTATE_CONNECTING:
626 /* OK, we got activity while connecting, so we're going to send some
627 * request depending on scan type. However, we can reregister everything
628 * here to save duplicate code: This code is common for all handlers */
629
630 /* Delete the old handler */
631 deregisterhandler(fd,0);
632 /* Set the new one */
633 registerhandler(fd,POLLERR|POLLHUP|POLLIN,&handlescansock);
634 sp->sch=scheduleoneshot(time(NULL)+SCANTIMEOUT,&timeoutscansock,(void *)sp);
635 /* Update state */
636 sp->state=SSTATE_SENTREQUEST;
637
638 switch(sp->type) {
639 case STYPE_HTTP:
640 sprintf(buf,"CONNECT %s:%d HTTP/1.0\r\n\r\n",myipstr->content,listenport);
641 if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
642 /* We didn't write the full amount, DIE */
643 killsock(sp,SOUTCOME_CLOSED);
644 return;
645 }
646 break;
647
648 case STYPE_SOCKS4:
649 /* set up the buffer */
650 netip=htonl(myip);
651 netport=htons(listenport);
652 memcpy(&buf[4],&netip,4);
653 memcpy(&buf[2],&netport,2);
654 buf[0]=4;
655 buf[1]=1;
656 buf[8]=0;
657 if ((write(fd,buf,9))<9) {
658 /* Didn't write enough, give up */
659 killsock(sp,SOUTCOME_CLOSED);
660 return;
661 }
662 break;
663
664 case STYPE_SOCKS5:
665 /* Set up initial request buffer */
666 buf[0]=5;
667 buf[1]=1;
668 buf[2]=0;
669 if ((write(fd,buf,3))>3) {
670 /* Didn't write enough, give up */
671 killsock(sp,SOUTCOME_CLOSED);
672 return;
673 }
674
675 /* Now the actual connect request */
676 buf[0]=5;
677 buf[1]=1;
678 buf[2]=0;
679 buf[3]=1;
680 netip=htonl(myip);
681 netport=htons(listenport);
682 memcpy(&buf[4],&netip,4);
683 memcpy(&buf[8],&netport,2);
684 res=write(fd,buf,10);
685 if (res<10) {
686 killsock(sp,SOUTCOME_CLOSED);
687 return;
688 }
689 break;
690
691 case STYPE_WINGATE:
692 /* Send wingate request */
693 sprintf(buf,"%s:%d\r\n",myipstr->content,listenport);
694 if((write(fd,buf,strlen(buf)))<strlen(buf)) {
695 killsock(sp,SOUTCOME_CLOSED);
696 return;
697 }
698 break;
699
700 case STYPE_CISCO:
701 /* Send cisco request */
702 sprintf(buf,"cisco\r\n");
703 if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
704 killsock(sp, SOUTCOME_CLOSED);
705 return;
706 }
707
708 sprintf(buf,"telnet %s %d\r\n",myipstr->content,listenport);
709 if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
710 killsock(sp, SOUTCOME_CLOSED);
711 return;
712 }
713
905c2ba2 714 break;
715
716 case STYPE_DIRECT:
717 /* Do nothing */
c86edd1d 718 break;
c7be40f8
CP
719
720 case STYPE_DIRECT_IRC:
721 sprintf(buf,"PRIVMSG\r\n");
722 if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
723 killsock(sp, SOUTCOME_CLOSED);
724 return;
725 }
726
e95140be
CP
727 /* Do nothing */
728 break;
729
730 case STYPE_ROUTER:
731 sprintf(buf,"GET /nonexistent HTTP/1.0\r\n\r\n");
732 if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
733 killsock(sp, SOUTCOME_CLOSED);
734 return;
735 }
736
c7be40f8
CP
737 /* Do nothing */
738 break;
c86edd1d
Q
739 }
740 break;
741
742 case SSTATE_SENTREQUEST:
743 res=read(fd, sp->readbuf+sp->bytesread, PSCAN_READBUFSIZE-sp->bytesread);
744
745 if (res<=0) {
746 if ((errno!=EINTR && errno!=EWOULDBLOCK) || res==0) {
747 /* EOF, forget it */
748 killsock(sp, SOUTCOME_CLOSED);
749 return;
750 }
751 }
752
753 sp->bytesread+=res;
754 sp->totalbytesread+=res;
c7be40f8
CP
755
756 {
757 char *magicstring;
758 int magicstringlength;
759
e95140be 760 if(sp->type == STYPE_DIRECT_IRC) {
c7be40f8
CP
761 magicstring = MAGICIRCSTRING;
762 magicstringlength = MAGICIRCSTRINGLENGTH;
e95140be
CP
763 } else if(sp->type == STYPE_ROUTER) {
764 magicstring = MAGICROUTERSTRING;
765 magicstringlength = MAGICROUTERSTRINGLENGTH;
766 } else {
767 magicstring = MAGICSTRING;
768 magicstringlength = MAGICSTRINGLENGTH;
c7be40f8
CP
769 }
770
771 for (i=0;i<sp->bytesread - magicstringlength;i++) {
772 if (!strncmp(sp->readbuf+i, magicstring, magicstringlength)) {
773 /* Found the magic string */
774 /* If the offset is 0, this means it was the first thing we got from the socket,
775 * so it's an actual IRCD (sheesh). Note that when the buffer is full and moved,
776 * the thing moved to offset 0 would previously have been tested as offset
777 * PSCAN_READBUFSIZE/2.
778 *
779 * Skip this checking for STYPE_DIRECT scans, which are used to detect trojans setting
780 * up portforwards (which will therefore show up as ircds, we rely on the port being
781 * strange enough to avoid false positives */
782 if (i==0 && (sp->type != STYPE_DIRECT)) {
783 killsock(sp, SOUTCOME_CLOSED);
784 return;
785 }
786
787 killsock(sp, SOUTCOME_OPEN);
c86edd1d
Q
788 return;
789 }
c86edd1d
Q
790 }
791 }
792
793 /* If the buffer is full, move half of it along to make room */
794 if (sp->bytesread == PSCAN_READBUFSIZE) {
795 memcpy(sp->readbuf, sp->readbuf + (PSCAN_READBUFSIZE)/2, PSCAN_READBUFSIZE/2);
796 sp->bytesread = PSCAN_READBUFSIZE/2;
797 }
798
799 /* Don't read data forever.. */
800 if (sp->totalbytesread > READ_SANITY_LIMIT) {
801 killsock(sp, SOUTCOME_CLOSED);
802 return;
803 }
804
805 /* No magic string yet, we schedule another timeout in case it comes later. */
806 sp->sch=scheduleoneshot(time(NULL)+SCANTIMEOUT,&timeoutscansock,(void *)sp);
807 return;
808 }
809}
810
811void killallscans() {
812 int i;
813 scan *sp;
814 cachehost *chp;
815
816 for(i=0;i<SCANHASHSIZE;i++) {
817 for(sp=scantable[i];sp;sp=sp->next) {
818 /* If there is a pending scan, delete it's clean host record.. */
a8ba1373
P
819 if ((chp=findcachehost(sp->node)) && !chp->proxies) {
820 sp->node->exts[ps_cache_ext] = NULL;
821 derefnode(iptree,sp->node);
c86edd1d 822 delcachehost(chp);
a8ba1373 823 }
c86edd1d
Q
824
825 if (sp->fd!=-1) {
826 deregisterhandler(sp->fd,1);
827 deleteschedule(sp->sch,&timeoutscansock,(void *)(sp));
828 }
829 }
830 }
831}
832
833void proxyscanstats(int hooknum, void *arg) {
834 char buf[512];
835
836 sprintf(buf, "Proxyscn: %6d/%4d scans complete/in progress. %d hosts queued.",
837 scansdone,activescans,queuedhosts);
838 triggerhook(HOOK_CORE_STATSREPLY,buf);
839 sprintf(buf, "Proxyscn: %6u known clean hosts",cleancount());
840 triggerhook(HOOK_CORE_STATSREPLY,buf);
841}
842
843void sendlagwarning() {
844 int i,j;
845 nick *np;
846
847 for (i=0;i<MAXSERVERS;i++) {
848 if (serverlist[i].maxusernum>0) {
849 for(j=0;j<serverlist[i].maxusernum;j++) {
850 np=servernicks[i][j];
851 if (np!=NULL && IsOper(np)) {
852 sendnoticetouser(proxyscannick,np,"Warning: More than 20,000 hosts to scan - I'm lagging behind badly!");
853 }
854 }
855 }
856 }
857}
858
905c2ba2 859int pscansort(const void *a, const void *b) {
860 int ra = *((const int *)a);
861 int rb = *((const int *)b);
862
863 return thescans[ra].hits - thescans[rb].hits;
864}
865
7ab80d0c
P
866int proxyscandostatus(void *sender, int cargc, char **cargv) {
867 nick *np = (nick *) sender;
c86edd1d
Q
868 int i;
869 int totaldetects=0;
905c2ba2 870 int ord[PSCAN_MAXSCANS];
c86edd1d 871
2220c058 872 sendnoticetouser(proxyscannick,np,"Service uptime: %s",longtoduration(time(NULL)-ps_starttime, 1));
c86edd1d
Q
873 sendnoticetouser(proxyscannick,np,"Total scans completed: %d",scansdone);
874 sendnoticetouser(proxyscannick,np,"Total hosts glined: %d",glinedhosts);
875
c651da74 876 sendnoticetouser(proxyscannick,np,"pendingscan structures: %lu x %lu bytes = %lu bytes total",countpendingscan,
92f1d9e3
D
877 sizeof(pendingscan), (countpendingscan * sizeof(pendingscan)));
878
c86edd1d 879 sendnoticetouser(proxyscannick,np,"Currently active scans: %d/%d",activescans,maxscans);
92f1d9e3 880 sendnoticetouser(proxyscannick,np,"Processing speed: %lu scans per minute",scanspermin);
c86edd1d
Q
881 sendnoticetouser(proxyscannick,np,"Normal queued scans: %d",normalqueuedscans);
882 sendnoticetouser(proxyscannick,np,"Timed queued scans: %d",prioqueuedscans);
883 sendnoticetouser(proxyscannick,np,"'Clean' cached hosts: %d",cleancount());
884 sendnoticetouser(proxyscannick,np,"'Dirty' cached hosts: %d",dirtycount());
557c8cb2
P
885
886 sendnoticetouser(proxyscannick,np,"Extra scans: %d", extrascancount());
c86edd1d
Q
887 for (i=0;i<5;i++)
888 sendnoticetouser(proxyscannick,np,"Open proxies, class %1d: %d/%d (%.2f%%)",i,hitsbyclass[i],scansbyclass[i],((float)hitsbyclass[i]*100)/scansbyclass[i]);
889
890 for (i=0;i<numscans;i++)
891 totaldetects+=thescans[i].hits;
892
905c2ba2 893 for (i=0;i<numscans;i++)
894 ord[i]=i;
895
896 qsort(ord,numscans,sizeof(int),pscansort);
897
c86edd1d
Q
898 sendnoticetouser(proxyscannick,np,"Scan type Port Detections");
899 for (i=0;i<numscans;i++)
900 sendnoticetouser(proxyscannick,np,"%-9s %-5d %d (%.2f%%)",
905c2ba2 901 scantostr(thescans[ord[i]].type), thescans[ord[i]].port, thescans[ord[i]].hits, ((float)thescans[ord[i]].hits*100)/totaldetects);
c86edd1d
Q
902
903 sendnoticetouser(proxyscannick,np,"End of list.");
7ab80d0c 904 return CMD_OK;
c86edd1d
Q
905}
906
7ab80d0c 907int proxyscandebug(void *sender, int cargc, char **cargv) {
c86edd1d
Q
908 /* Dump all scans.. */
909 int i;
910 int activescansfound=0;
911 int totalscansfound=0;
912 scan *sp;
7ab80d0c 913 nick *np = (nick *)sender;
c86edd1d
Q
914
915 sendnoticetouser(proxyscannick,np,"Active scans : %d",activescans);
916
917 for (i=0;i<SCANHASHSIZE;i++) {
918 for (sp=scantable[i];sp;sp=sp->next) {
919 if (sp->outcome==SOUTCOME_INPROGRESS) {
920 activescansfound++;
921 }
922 totalscansfound++;
923 sendnoticetouser(proxyscannick,np,"fd: %d type: %d port: %d state: %d outcome: %d IP: %s",
557c8cb2 924 sp->fd,sp->type,sp->port,sp->state,sp->outcome,IPtostr(((patricia_node_t *)sp->node)->prefix->sin));
c86edd1d
Q
925 }
926 }
927
7ab80d0c
P
928 sendnoticetouser(proxyscannick,np,"Total %d scans actually found (%d active)",totalscansfound,activescansfound);
929 return CMD_OK;
930}
931
932void proxyscan_onconnect(int hooknum, void *arg) {
933 ps_ready = 1;
934
935 /* kick the queue.. */
936 startqueuedscans();
937}
938
939int proxyscandosave(void *sender, int cargc, char **cargv) {
940 nick *np = (nick *)sender;
941
942 sendnoticetouser(proxyscannick,np,"Saving cached hosts...");
943 dumpcachehosts(NULL);
944 sendnoticetouser(proxyscannick,np,"Done.");
945 return CMD_OK;
946}
947
948int proxyscandospew(void *sender, int cargc, char **cargv) {
949 nick *np = (nick *)sender;
950
5de2923d
CP
951 if(cargc < 1)
952 return CMD_USAGE;
953
7ab80d0c
P
954 /* check our database for the ip supplied */
955 unsigned long a,b,c,d;
956 if (4 != sscanf(cargv[0],"%lu.%lu.%lu.%lu",&a,&b,&c,&d)) {
957 sendnoticetouser(proxyscannick,np,"Usage: spew x.x.x.x");
958 } else {
959 /* check db */
960 proxyscanspewip(proxyscannick,np,a,b,c,d);
961 }
962 return CMD_OK;
963}
964
965int proxyscandoshowkill(void *sender, int cargc, char **cargv) {
966 nick *np = (nick *)sender;
967
5de2923d
CP
968 if(cargc < 1)
969 return CMD_USAGE;
970
7ab80d0c
P
971 /* check our database for the id supplied */
972 unsigned long a;
973 if (1 != sscanf(cargv[0],"%lu",&a)) {
974 sendnoticetouser(proxyscannick,np,"Usage: showkill <id>");
975 } else {
976 /* check db */
977 proxyscanshowkill(proxyscannick,np,a);
978 }
979 return CMD_OK;
980}
981
883d13a2
CP
982void startnickscan(nick *np) {
983 time_t t = time(NULL);
984 int i;
985 for(i=0;i<numscans;i++) {
986 /* @@@TODO: we allow a forced scan to scan the same IP multiple times atm */
987 queuescan(np->ipnode,thescans[i].type,thescans[i].port,SCLASS_NORMAL,t);
988 }
989}
990
7ab80d0c
P
991int proxyscandoscan(void *sender, int cargc, char **cargv) {
992 nick *np = (nick *)sender;
993 patricia_node_t *node;
994 struct irc_in_addr sin;
995 unsigned char bits;
996 int i;
997
5de2923d
CP
998 if(cargc < 1)
999 return CMD_USAGE;
1000
7ab80d0c
P
1001 if (0 == ipmask_parse(cargv[0],&sin, &bits)) {
1002 sendnoticetouser(proxyscannick,np,"Usage: scan <ip>");
1003 } else {
3e986f5e
CP
1004 if (bits != 128 || irc_in_addr_is_loopback(&sin)) {
1005 sendnoticetouser(proxyscannick,np,"You may only scan single IP's");
9ae689d8
P
1006 return CMD_OK;
1007 }
1008
883d13a2 1009 time_t t;
7ab80d0c
P
1010 sendnoticetouser(proxyscannick,np,"Forcing scan of %s",IPtostr(sin));
1011 // * Just queue the scans directly here.. plonk them on the priority queue * /
1012 node = refnode(iptree, &sin, bits); /* node leaks node here - should only allow to scan a nick? */
883d13a2 1013 t = time(NULL);
7ab80d0c
P
1014 for(i=0;i<numscans;i++) {
1015 /* @@@TODO: we allow a forced scan to scan the same IP multiple times atm */
883d13a2 1016 queuescan(node,thescans[i].type,thescans[i].port,SCLASS_NORMAL,t);
557c8cb2 1017 }
7ab80d0c
P
1018 }
1019 return CMD_OK;
1020}
557c8cb2 1021
7ab80d0c
P
1022int proxyscandoaddscan(void *sender, int cargc, char **cargv) {
1023 nick *np = (nick *)sender;
1024
5de2923d
CP
1025 if(cargc < 1)
1026 return CMD_USAGE;
1027
7ab80d0c
P
1028 unsigned int a,b;
1029 if (sscanf(cargv[0],"%u %u",&a,&b) != 2) {
1030 sendnoticetouser(proxyscannick,np,"Usage: addscan <type> <port>");
1031 } else {
1032 sendnoticetouser(proxyscannick,np,"Added scan type %u port %u",a,b);
1033 proxyscan_addscantype(a,b);
1034 scanall(a,b);
1035 }
1036 return CMD_OK;
1037}
1038
1039int proxyscandodelscan(void *sender, int cargc, char **cargv) {
1040 nick *np = (nick *)sender;
1041
5de2923d
CP
1042 if(cargc < 1)
1043 return CMD_USAGE;
1044
7ab80d0c
P
1045 unsigned int a,b;
1046 if (sscanf(cargv[0],"%u %u",&a,&b) != 2) {
1047 sendnoticetouser(proxyscannick,np,"Usage: delscan <type> <port>");
1048 } else {
1049 sendnoticetouser(proxyscannick,np,"Delete scan type %u port %u",a,b);
1050 proxyscan_delscantype(a,b);
1051 }
1052 return CMD_OK;
1053}
1054
1055int proxyscandoshowcommands(void *sender, int cargc, char **cargv) {
1056 nick *np = (nick *)sender;
1057 Command *cmdlist[100];
1058 int i,n;
1059
1060 n=getcommandlist(ps_commands,cmdlist,100);
1061
1062 sendnoticetouser(proxyscannick,np,"The following commands are registered at present:");
1063 for(i=0;i<n;i++) {
1064 sendnoticetouser(proxyscannick,np,"%s",cmdlist[i]->command->content);
1065 }
1066 sendnoticetouser(proxyscannick,np,"End of list.");
1067 return CMD_OK;
c86edd1d 1068}