#include "../core/hooks.h"
#include "../server/server.h"
#include "../lib/strlfunc.h"
+#include "../glines/glines.h"
#include <stdint.h>
#define INSTANT_IDENT_GLINE 1
#define DELAYED_HOST_GLINE 5
#define DELAYED_KILL 6
-MODULE_VERSION("1.43");
+#define RESERVED_NICK_GLINE_DURATION 3600 /* 1h */
+
+MODULE_VERSION("1.44");
typedef struct rg_glinenode {
nick *np;
void rg_flush_schedule(void *arg);
static char *gvhost(nick *np);
+typedef void (scannick_fn)(struct rg_struct *, nick *, char *, void *);
+static void rg_scannick(nick *np, scannick_fn *fn, void *arg);
+static void rg_gline_match(struct rg_struct *rp, nick *np, char *hostname, void *arg);
static DBModuleIdentifier dbid;
static unsigned long highestid = 0;
static unsigned int getrgmarker(void);
+#define RESERVED_NICK_CLASS "reservednick"
/* shadowserver only reports classes[0] */
-static const char *classes[] = { "drone", "proxy", "spam", "fakeauth", "other", (char *)0 };
+static const char *classes[] = { "drone", "proxy", "spam", "other", RESERVED_NICK_CLASS, (char *)0 };
+
+void rg_initglinelist(struct rg_glinelist *gll);
+void rg_flushglines(struct rg_glinelist *gll);
void _init(void) {
sstring *max_casualties, *max_spew, *expiry_time, *max_per_gline;
Error("regexgline", ERR_STOP, "Could not connect to database.");
}
}
-
+
+static void rg_count_match(struct rg_struct *rp, nick *np, char *hostname, void *arg) {
+ void **varg = (void **)arg;
+ int *count = (int *)varg[0];
+
+ (*count)++;
+}
+
+static void rg_gline_reply_match(struct rg_struct *rp, nick *np, char *hostname, void *arg) {
+ void **varg = (void **)arg;
+
+ rg_count_match(rp, np, hostname, arg);
+ rg_gline_match(rp, np, hostname, varg[1]);
+}
+
+int rg_rescan(void *source, int cargc, char **cargv) {
+ int gline = 0;
+ int j;
+ nick *np = (nick *)source, *tnp;
+ void *arg[2];
+ int count = 0;
+ struct rg_glinelist gll;
+ scannick_fn *fn;
+
+ if(cargc > 0)
+ gline = !strcmp(cargv[0], "-g");
+
+ arg[0] = &count;
+
+ if(gline == 0) {
+ fn = rg_count_match;
+ } else {
+ controlreply(np, "G-line mode activated.");
+
+ rg_initglinelist(&gll);
+ arg[1] = &gll;
+
+ fn = rg_gline_reply_match;
+ }
+
+ controlreply(np, "Beginning scan, this may take a while...");
+
+ for(j=0;j<NICKHASHSIZE;j++)
+ for(tnp=nicktable[j];tnp;tnp=tnp->next)
+ rg_scannick(tnp, fn, arg);
+
+ controlreply(np, "Scan completed, %d hits.", count);
+
+ if(gline)
+ rg_flushglines(&gll);
+
+ return CMD_OK;
+}
+
void _fini(void) {
- struct rg_struct *gp = rg_list, *oldgp;
+ struct rg_struct *gp, *oldgp;
rg_delay *delay, *delaynext;
if(started) {
deregisterhook(HOOK_NICK_NEWNICK, &rg_nick);
- deregisterhook(HOOK_NICK_RENAME, &rg_nick);
+ deregisterhook(HOOK_NICK_RENAME, &rg_rename);
deregisterhook(HOOK_NICK_LOSTNICK, &rg_lostnick);
deregistercontrolcmd("regexspew", rg_spew);
deregistercontrolcmd("regexglist", rg_glist);
deregistercontrolcmd("regexdelgline", rg_delgline);
deregistercontrolcmd("regexgline", rg_gline);
deregistercontrolcmd("regexidlookup", rg_idlist);
+ deregistercontrolcmd("regexrescan", rg_rescan);
}
if(rg_delays) {
rg_delay *delay = (rg_delay *)arg;
char hostname[RG_MASKLEN];
int hostlen, usercount = 0;
+ char reason[200];
+ int glineflags = 0;
/* User or regex gline no longer exists */
if((!delay->np) || (!delay->reason)) {
if (delay->reason->type == DELAYED_HOST_GLINE) {
usercount = delay->np->host->clonecount;
- snprintf(hostname, sizeof(hostname), "*@%s", IPtostr(delay->np->p_ipaddr));
}
if((delay->reason->type == DELAYED_IDENT_GLINE) || (usercount > rg_max_per_gline)) {
if(!ircd_strcmp(delay->np->ident, tnp->ident))
usercount++;
- snprintf(hostname, sizeof(hostname), "%s@%s", delay->np->ident, IPtostr(delay->np->p_ipaddr));
+ glineflags = GLINE_ALWAYS_USER;
}
if ((delay->reason->type == DELAYED_KILL) || (usercount > rg_max_per_gline)) {
}
rg_shadowserver(delay->np, delay->reason, delay->reason->type);
- irc_send("%s GL * +%s %d %jd :AUTO: %s (ID: %08lx)\r\n", mynumeric->content, hostname, rg_expiry_time, (intmax_t)time(NULL), delay->reason->reason->content, delay->reason->glineid);
+ snprintf(reason, sizeof(reason), "AUTO: %s (ID: %08lx)", delay->reason->reason->content, delay->reason->glineid);
+ glinebynick(delay->np, rg_expiry_time, reason, glineflags, "regexgline");
rg_deletedelay(delay);
}
"3 - Instant KILL (ik)\n"
"4 - Delayed USER@IP GLINE (dgu)\n"
"5 - Delayed *@IP GLINE (dgh)\n"
- "6 - Delayed KILL (dk)",
+ "6 - Delayed KILL (dk)\n"
+ "Note that some classes may have additional side effects (e.g. 'reservednick' also sets nick style glines).",
allclasses);
registercontrolhelpcmd("regexgline", NO_OPER, 5, &rg_gline, helpbuf);
registercontrolhelpcmd("regexglist", NO_OPER, 1, &rg_glist, "Usage: regexglist <pattern>\nLists regular expression patterns.");
registercontrolhelpcmd("regexspew", NO_OPER, 1, &rg_spew, "Usage: regexspew <pattern>\nLists users currently on the network which match the given pattern.");
registercontrolhelpcmd("regexidlookup", NO_OPER, 1, &rg_idlist, "Usage: regexidlookup <id>\nFinds a regular expression pattern by it's ID number.");
+ registercontrolhelpcmd("regexrescan", NO_OPER, 1, &rg_rescan, "Usage: regexrescan ?-g?\nRescans the net for missed clients, optionally glining matches (used for debugging).");
registerhook(HOOK_NICK_NEWNICK, &rg_nick);
- registerhook(HOOK_NICK_RENAME, &rg_nick);
+ registerhook(HOOK_NICK_RENAME, &rg_rename);
registerhook(HOOK_NICK_LOSTNICK, &rg_lostnick);
rg_startup();
dbloadtable("regexgline.glines", NULL, dbloaddata, dbloadfini);
}
-void rg_nick(int hooknum, void *arg) {
- nick *np = (nick *)arg;
+static void rg_scannick(nick *np, scannick_fn *fn, void *arg) {
struct rg_struct *rp;
char hostname[RG_MASKLEN];
int hostlen;
- struct rg_glinelist gll;
-
- rg_initglinelist(&gll);
-
- hostlen = RGBuildHostname(hostname, np);
if(ignorable_nick(np))
return;
+ hostlen = RGBuildHostname(hostname, np);
+
for(rp=rg_list;rp;rp=rp->next) {
if(pcre_exec(rp->regex, rp->hint, hostname, hostlen, 0, 0, NULL, 0) >= 0) {
- rg_dogline(&gll, np, rp, hostname);
+ fn(rp, np, hostname, arg);
break;
}
}
+}
+
+static void rg_gline_match(struct rg_struct *rp, nick *np, char *hostname, void *arg) {
+ struct rg_glinelist *gll = (struct rg_glinelist *)arg;
+
+ rg_dogline(gll, np, rp, hostname);
+}
+
+void rg_rename(int hooknum, void *arg) {
+ void **harg = (void **)arg;
+ rg_nick(hooknum, harg[0]);
+}
+
+void rg_nick(int hooknum, void *arg) {
+ nick *np = (nick *)arg;
+ struct rg_glinelist gll;
+
+ rg_initglinelist(&gll);
+
+ rg_scannick(np, rg_gline_match, &gll);
rg_flushglines(&gll);
}
}
void rg_startup(void) {
- int j, hostlen;
+ int j;
nick *np;
- struct rg_struct *rp;
struct rg_glinelist gll;
- char hostname[RG_MASKLEN];
rg_initglinelist(&gll);
- for(j=0;j<NICKHASHSIZE;j++) {
- for(np=nicktable[j];np;np=np->next) {
- if(ignorable_nick(np))
- continue;
- hostlen = RGBuildHostname(hostname, np);
- for(rp=rg_list;rp;rp=rp->next) {
- if(pcre_exec(rp->regex, rp->hint, hostname, hostlen, 0, 0, NULL, 0) >= 0) {
- rg_dogline(&gll, np, rp, hostname);
- break;
- }
- }
- }
- }
+ for(j=0;j<NICKHASHSIZE;j++)
+ for(np=nicktable[j];np;np=np->next)
+ rg_scannick(np, rg_gline_match, &gll);
rg_flushglines(&gll);
}
}
int __rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched) { /* PPA: if multiple users match the same user@host or *@host it'll send multiple glines?! */
- char hostname[RG_MASKLEN];
int usercount = 0;
int validdelay;
+ char reason[200];
+ int glineflags = 0;
rg_loggline(rp, np);
if (rp->type == INSTANT_HOST_GLINE) {
usercount = np->host->clonecount;
- snprintf(hostname, sizeof(hostname), "*@%s", IPtostr(np->p_ipaddr));
}
if ((rp->type == INSTANT_IDENT_GLINE) || (usercount > rg_max_per_gline)) {
if(!ircd_strcmp(np->ident, tnp->ident))
usercount++;
- snprintf(hostname, sizeof(hostname), "%s@%s", np->ident, IPtostr(np->p_ipaddr));
+ glineflags = GLINE_ALWAYS_USER;
+ }
+
+ if(!strcmp(rp->class, RESERVED_NICK_CLASS)) {
+ char reason[512];
+ snprintf(reason, sizeof(reason), "AUTO %s (ID: %08lx)", rp->reason->content, rp->glineid);
+ glinebynick(np, RESERVED_NICK_GLINE_DURATION, reason, GLINE_ALWAYS_NICK, "regexgline");
}
validdelay = (rp->type == INSTANT_KILL) || (rp->type == DELAYED_IDENT_GLINE) || (rp->type == DELAYED_HOST_GLINE) || (rp->type == DELAYED_KILL);
}
rg_shadowserver(np, rp, rp->type);
- irc_send("%s GL * +%s %d %jd :AUTO: %s (ID: %08lx)\r\n", mynumeric->content, hostname, rg_expiry_time, (intmax_t)time(NULL), rp->reason->content, rp->glineid);
+ snprintf(reason, sizeof(reason), "AUTO: %s (ID: %08lx)", rp->reason->content, rp->glineid);
+ glinebynick(np, rg_expiry_time, reason, glineflags, "regexgline");
return usercount;
}