]> jfr.im git - irc/quakenet/newserv.git/blobdiff - proxyscan/proxyscan.c
PROXYSCAN: Add port 6666 and change scan type displayed reason.
[irc/quakenet/newserv.git] / proxyscan / proxyscan.c
index ec3a89f7ae396d4cefc140308bcf46beface6bd8..648e97ac56e72dcbe95f48527943d759d97f3cbb 100644 (file)
@@ -24,6 +24,8 @@
 #include "../lib/version.h"
 #include "../channel/channel.h"
 #include "../localuser/localuserchannel.h"
+#include "../core/nsmalloc.h"
+#include "../lib/irc_ipv6.h"
 
 MODULE_VERSION("")
 
@@ -37,6 +39,8 @@ MODULE_VERSION("")
 
 scan *scantable[SCANHASHSIZE];
 
+CommandTree *ps_commands;
+
 int listenfd;
 int activescans;
 int maxscans;
@@ -46,6 +50,9 @@ int rescaninterval;
 int warningsent;
 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];
@@ -77,18 +84,27 @@ 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 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 */
   
@@ -125,6 +141,19 @@ void _init(void) {
   int ipbits[4];
 
   ps_start_ts = time(NULL);
+  ps_ready = 0;
+  ps_commands = NULL;
+
+  ps_cache_ext = registernodeext("proxyscancache");
+  if( ps_cache_ext == -1 ) {
+    Error("proxyscan",ERR_INFO,"failed to reg node ext");
+    return;
+  }
+  ps_extscan_ext = registernodeext("proxyscanextscan");
+  if ( ps_extscan_ext == -1) { 
+    Error("proxyscan",ERR_INFO,"failed to reg node ext");
+    return;
+  }
 
   memset(scantable,0,sizeof(scantable));
   maxscans=200;
@@ -134,7 +163,7 @@ void _init(void) {
   warningsent=0;
   ps_starttime=time(NULL);
   glinedhosts=0;
-
   scanspermin=0;
   lastscants=time(NULL);
 
@@ -162,10 +191,10 @@ void _init(void) {
   myip=((ipbits[0]&0xFF)<<24)+((ipbits[1]&0xFF)<<16)+
     ((ipbits[2]&0xFF)<<8)+(ipbits[3]&0xFF);
 
+#if defined(PROXYSCAN_MAIL)
   /* Mailer host */
   cfgstr=getcopyconfigitem("proxyscan","mailerip","",16);
   
-#if defined(PROXYSCAN_MAIL)
   psm_mailerfd=-1;
   if (cfgstr) {
     sscanf(cfgstr->content,"%d.%d.%d.%d",&ipbits[0],&ipbits[1],&ipbits[2],&ipbits[3]);
@@ -186,6 +215,8 @@ void _init(void) {
   /* Set up our nick on the network */
   scheduleoneshot(time(NULL),&registerproxyscannick,NULL);
 
+  registerhook(HOOK_SERVER_END_OF_BURST, &proxyscan_onconnect);
+
   registerhook(HOOK_NICK_NEWNICK,&proxyscan_newnick);
 
   registerhook(HOOK_CORE_STATSREQUEST,&proxyscanstats);
@@ -193,6 +224,9 @@ void _init(void) {
   /* Read in the clean hosts */
   loadcachehosts();
 
+  /* Read in any custom ports to scan */
+  loadextrascans();
+
   /* Set up the database */
   if ((proxyscandbinit())!=0) {
     brokendb=1;
@@ -200,6 +234,17 @@ 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, 0, &proxyscandospew);
+  addcommandtotree(ps_commands, "showkill", 0, 0, &proxyscandoshowkill);
+  addcommandtotree(ps_commands, "scan", 0, 0, &proxyscandoscan);
+  addcommandtotree(ps_commands, "addscan", 0, 0, &proxyscandoaddscan);
+  addcommandtotree(ps_commands, "delscan", 0, 0, &proxyscandodelscan);
+
   /* Default scan types */
   proxyscan_addscantype(STYPE_HTTP, 8080);
   proxyscan_addscantype(STYPE_HTTP, 80);
@@ -233,13 +278,23 @@ void _init(void) {
   proxyscan_addscantype(STYPE_HTTP, 65506);
   proxyscan_addscantype(STYPE_HTTP, 63809);
   proxyscan_addscantype(STYPE_HTTP, 63000);
-  proxyscan_addscantype(STYPE_SOCKS4, 559);
   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);
   /* 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) {
@@ -274,22 +329,31 @@ void registerproxyscannick(void *arg) {
 void _fini(void) {
 
   deregisterlocaluser(proxyscannick,NULL);
+  
+  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 */
-  sfreeall();
+  nsfreeall(POOL_PROXYSCAN);
   
+  freesstring(myipstr);
   freesstring(ps_mailname);
 #if defined(PROXYSCAN_MAIL)
   if (psm_mailerfd!=-1)
@@ -302,8 +366,9 @@ void _fini(void) {
 
 void proxyscanuserhandler(nick *target, int message, void **params) {
   nick *sender;
-  char *msg;
-  int i;
+  Command *ps_command;
+  char *cargv[20];
+  int cargc;
 
   switch(message) {
   case LU_KILLED:
@@ -314,93 +379,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 <id>");
-        } else {
-          /* check db */
-          proxyscanshowkill(proxyscannick,sender,a);
-        }
-      }
+      ps_command = findcommandintree(ps_commands, cargv[0], 1);
 
-      if (!ircd_strncmp(msg,"scan ",5)) {
-        unsigned long a,b,c,d;
-        if (4 != sscanf(&msg[5],"%lu.%lu.%lu.%lu",&a,&b,&c,&d)) {
-          sendnoticetouser(proxyscannick,sender,"Usage: scan a.b.c.d");
-        } else {
-          sendnoticetouser(proxyscannick,sender,"Forcing scan of %lu.%lu.%lu.%lu",a,b,c,d);
-         /* Just queue the scans directly here.. plonk them on the priority queue */
-         for(i=0;i<numscans;i++) {
-           queuescan((a<<24)+(b<<16)+(c<<8)+d,thescans[i].type,thescans[i].port,SCLASS_NORMAL,time(NULL));
-         }
-        }      
+      if ( !ps_command ) {
+        sendnoticetouser(proxyscannick,sender, "Unknown command.");
+        return;
       }
 
-      if (!ircd_strncmp(msg,"addscan ",8)) {
-       unsigned int a,b;
-       if (sscanf(msg+8,"%u %u",&a,&b) != 2) {
-         sendnoticetouser(proxyscannick,sender,"Usage: addscan <type> <port>");
-       } 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 <type> <port>");
-       } 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 <ip>         Force scan of the supplied IP");
-       sendnoticetouser(proxyscannick,sender,"spew <ip>         Find <ip> in our list of open proxies");
-       sendnoticetouser(proxyscannick,sender,"showkill <id>     Shows details of a kill or gline made by the service");
-      }
+      (ps_command->handler)((void *)sender, cargc - 1, &(cargv[1]));
+      break;
     }
 
   default:
@@ -447,9 +446,8 @@ scan *findscan(int fd) {
   return NULL;
 }
 
-void startscan(unsigned int IP, int type, int port, int class) {
+void startscan(patricia_node_t *node, int type, int port, int class) {
   scan *sp;
-
   float scantmp;
 
   if (scansdone>maxscans)
@@ -472,17 +470,18 @@ void startscan(unsigned int IP, int type, int port, int class) {
   
   sp->outcome=SOUTCOME_INPROGRESS;
   sp->port=port;
-  sp->IP=IP;
+  sp->node=node;
   sp->type=type;
   sp->class=class;
   sp->bytesread=0;
   sp->totalbytesread=0;
   memset(sp->readbuf, '\0', PSCAN_READBUFSIZE);
 
-  sp->fd=createconnectsocket(sp->IP,sp->port);
+  sp->fd=createconnectsocket(irc_in_addr_v4_to_int(&((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;
   }
@@ -518,21 +517,23 @@ void killsock(scan *sp, int outcome) {
   if (sp->outcome==SOUTCOME_CLOSED &&
       ((sp->class==SCLASS_CHECK) ||
        (sp->class==SCLASS_NORMAL && (sp->state==SSTATE_SENTREQUEST || sp->state==SSTATE_GOTRESPONSE))))
-    queuescan(sp->IP, sp->type, sp->port, SCLASS_PASS2, time(NULL)+300);
+    queuescan(sp->node, sp->type, sp->port, SCLASS_PASS2, time(NULL)+300);
 
   if (sp->outcome==SOUTCOME_CLOSED && sp->class==SCLASS_PASS2)
-    queuescan(sp->IP, sp->type, sp->port, SCLASS_PASS3, time(NULL)+300);
+    queuescan(sp->node, sp->type, sp->port, SCLASS_PASS3, time(NULL)+300);
 
   if (sp->outcome==SOUTCOME_CLOSED && sp->class==SCLASS_PASS3)
-    queuescan(sp->IP, sp->type, sp->port, SCLASS_PASS4, time(NULL)+300);
+    queuescan(sp->node, sp->type, sp->port, SCLASS_PASS4, time(NULL)+300);
 
   if (sp->outcome==SOUTCOME_OPEN) {
     hitsbyclass[sp->class]++;
   
     /* Lets try and get the cache record.  If there isn't one, make a new one. */
-    if (!(chp=findcachehost(sp->IP)))
-      chp=addcleanhost(sp->IP, time(NULL));
-    
+    if (!(chp=findcachehost(sp->node))) {
+      chp=addcleanhost(time(NULL));
+      patricia_ref_prefix(sp->node->prefix);
+      sp->node->exts[ps_cache_ext] = chp;
+    }
     /* Stick it on the cache's list of proxies, if necessary */
     for (fpp=chp->proxies;fpp;fpp=fpp->next)
       if (fpp->type==sp->type && fpp->port==sp->port)
@@ -548,12 +549,12 @@ void killsock(scan *sp, int outcome) {
     
     if (!chp->glineid) {
       glinedhosts++;
-      loggline(chp);
-      irc_send("%s GL * +*@%s 1800 :Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d",
-              mynumeric->content,IPlongtostr(sp->IP),chp->glineid);
-      Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",IPlongtostr(sp->IP));
+      loggline(chp, sp->node);
+      irc_send("%s GL * +*@%s 1800 %jd :Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d",
+              mynumeric->content,IPtostr(((patricia_node_t *)sp->node)->prefix->sin),(intmax_t)getnettime(), chp->glineid);
+      Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",IPtostr(((patricia_node_t *)sp->node)->prefix->sin));
     } else {
-      loggline(chp);  /* Update log only */
+      loggline(chp, sp->node);  /* Update log only */
     }
 
     /* Update counter */
@@ -698,6 +699,16 @@ void handlescansock(int fd, short events) {
     case STYPE_DIRECT:
       /* Do nothing */
       break;    
+
+    case STYPE_DIRECT_IRC:
+      sprintf(buf,"PRIVMSG\r\n");
+      if ((write(fd,buf,strlen(buf)))<strlen(buf)) {
+       killsock(sp, SOUTCOME_CLOSED);
+        return;
+      }
+      
+      /* Do nothing */
+      break;    
     }                
     break;
     
@@ -714,24 +725,38 @@ void handlescansock(int fd, short events) {
     
     sp->bytesread+=res;
     sp->totalbytesread+=res;
-    for (i=0;i<sp->bytesread - 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);
+
+    {
+      char *magicstring;
+      int magicstringlength;
+
+      if(sp->type != STYPE_DIRECT_IRC) {
+        magicstring = MAGICSTRING;
+        magicstringlength = MAGICSTRINGLENGTH;
+      } else {
+        magicstring = MAGICIRCSTRING;
+        magicstringlength = MAGICIRCSTRINGLENGTH;
+      }
+
+      for (i=0;i<sp->bytesread - 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;
       }
     }
     
@@ -761,8 +786,11 @@ void killallscans() {
   for(i=0;i<SCANHASHSIZE;i++) {
     for(sp=scantable[i];sp;sp=sp->next) {
       /* If there is a pending scan, delete it's clean host record.. */
-      if ((chp=findcachehost(sp->IP)) && !chp->proxies)
+      if ((chp=findcachehost(sp->node)) && !chp->proxies) {
+        sp->node->exts[ps_cache_ext] = NULL;
+        derefnode(iptree,sp->node); 
         delcachehost(chp);
+      }
         
       if (sp->fd!=-1) {
        deregisterhandler(sp->fd,1);
@@ -805,7 +833,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];
@@ -823,7 +852,8 @@ void proxyscandostatus(nick *np) {
   sendnoticetouser(proxyscannick,np,"Timed queued scans:     %d",prioqueuedscans);
   sendnoticetouser(proxyscannick,np,"'Clean' cached hosts:   %d",cleancount());
   sendnoticetouser(proxyscannick,np,"'Dirty' cached hosts:   %d",dirtycount());
-  
+  sendnoticetouser(proxyscannick,np,"Extra scans: %d", extrascancount());
   for (i=0;i<5;i++)
     sendnoticetouser(proxyscannick,np,"Open proxies, class %1d:  %d/%d (%.2f%%)",i,hitsbyclass[i],scansbyclass[i],((float)hitsbyclass[i]*100)/scansbyclass[i]);
   
@@ -841,14 +871,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;
+  nick *np = (nick *)sender;
 
   sendnoticetouser(proxyscannick,np,"Active scans : %d",activescans);
   
@@ -859,9 +891,117 @@ void proxyscandebug(nick *np) {
       }
       totalscansfound++;
       sendnoticetouser(proxyscannick,np,"fd: %d type: %d port: %d state: %d outcome: %d IP: %s",
-                      sp->fd,sp->type,sp->port,sp->state,sp->outcome,IPlongtostr(sp->IP));
+                      sp->fd,sp->type,sp->port,sp->state,sp->outcome,IPtostr(((patricia_node_t *)sp->node)->prefix->sin));
     }
   }
 
   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;
+
+  /* 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;
+
+  /* check our database for the id supplied */
+  unsigned long a;
+  if (1 != sscanf(cargv[0],"%lu",&a)) {
+    sendnoticetouser(proxyscannick,np,"Usage: showkill <id>");
+  } else {
+    /* check db */
+    proxyscanshowkill(proxyscannick,np,a);
+  }
+  return CMD_OK;
+}
+
+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 (0 == ipmask_parse(cargv[0],&sin, &bits)) {
+    sendnoticetouser(proxyscannick,np,"Usage: scan <ip>");
+  } else {
+    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? */
+    for(i=0;i<numscans;i++) {
+      /* @@@TODO: we allow a forced scan to scan the same IP multiple times atm */
+      queuescan(node,thescans[i].type,thescans[i].port,SCLASS_NORMAL,time(NULL));
+    }
+  }
+  return CMD_OK;
+}
+
+int proxyscandoaddscan(void *sender, int cargc, char **cargv) {
+  nick *np = (nick *)sender;
+
+  unsigned int a,b;
+  if (sscanf(cargv[0],"%u %u",&a,&b) != 2) {
+    sendnoticetouser(proxyscannick,np,"Usage: addscan <type> <port>");
+  } 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;
+
+  unsigned int a,b;
+  if (sscanf(cargv[0],"%u %u",&a,&b) != 2) {
+    sendnoticetouser(proxyscannick,np,"Usage: delscan <type> <port>");
+  } 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;i<n;i++) {
+    sendnoticetouser(proxyscannick,np,"%s",cmdlist[i]->command->content);
+  }
+  sendnoticetouser(proxyscannick,np,"End of list.");
+  return CMD_OK;
 }