#include "../lib/stringbuf.h"
#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 INSTANT_HOST_GLINE 2
#define DELAYED_HOST_GLINE 5
#define DELAYED_KILL 6
-MODULE_VERSION("1.41");
+#define RESERVED_NICK_GLINE_DURATION 3600 /* 1h */
+
+MODULE_VERSION("1.44");
typedef struct rg_glinenode {
nick *np;
struct rg_delay *next;
} rg_delay;
+#define GLINE_HEADER " ID Expires Set by Class Type Last seen (ago) Hits(p) Hits Reason"
+
rg_delay *rg_delays;
void rg_setdelay(nick *np, struct rg_struct *reason, short punish);
void rg_dodelay(void *arg);
void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched);
+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 int attached = 0, started = 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) {
deleteschedule(rg_schedule, &rg_checkexpiry, NULL);
rg_schedule = NULL;
}
-
+
+ deleteallschedules(rg_flush_schedule);
+ rg_flush_schedule(NULL);
+
for(gp=rg_list;gp;) {
oldgp = gp;
gp = gp->next;
}
}
+static int ignorable_nick(nick *np) {
+ if(IsOper(np) || IsService(np) || IsXOper(np) || SIsService(&serverlist[homeserver(np->numeric)]))
+ return 1;
+ return 0;
+}
+
void rg_checkexpiry(void *arg) {
struct rg_struct *rp = rg_list, *lp = NULL;
time_t current = time(NULL);
while(rp) {
if (current >= rp->expires) {
+ dbquery("DELETE FROM regexglines WHERE id = %d", rp->id);
if (lp) {
lp->next = rp->next;
rg_freestruct(rp);
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)) {
- if (IsAccount(delay->np)) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed kill regex %08lx (class: %s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class);
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed kill regex %08lx (class: %s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class);
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched delayed kill regex %08lx (class: %s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class);
rg_shadowserver(delay->np, delay->reason, DELAYED_KILL);
killuser(NULL, delay->np, "%s (ID: %08lx)", delay->reason->reason->content, delay->reason->glineid);
}
if (delay->reason->type == DELAYED_IDENT_GLINE) {
- if (IsAccount(delay->np)) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
} else if (delay->reason->type == DELAYED_HOST_GLINE) {
- if (IsAccount(delay->np)) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":"");
} else {
return;
}
rg_shadowserver(delay->np, delay->reason, delay->reason->type);
- irc_send("%s GL * +%s %d %d :AUTO: %s (ID: %08lx)\r\n", mynumeric->content, hostname, rg_expiry_time, 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);
}
for(nn=gll->start;nn;nn=pn) {
pn = nn->next;
if(nn->punish == INSTANT_KILL) {
- if ( IsAccount(nn->np) ) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched kill regex %08lx (class: %s)", nn->np->nick, nn->np->ident, nn->np->host->name->content, nn->np->authname, nn->reason->glineid, nn->reason->class);
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched kill regex %08lx (class: %s)", nn->np->nick, nn->np->ident, nn->np->host->name->content, nn->reason->glineid, nn->reason->class);
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched kill regex %08lx (class: %s)", gvhost(nn->np), nn->reason->glineid, nn->reason->class);
rg_shadowserver(nn->np, nn->reason, nn->punish);
killuser(NULL, nn->np, "%s (ID: %08lx)", nn->reason->reason->content, nn->reason->glineid);
return;
}
- if (dbnumfields(dbres) != 7) {
+ if (dbnumfields(dbres) != 9) {
Error("regexgline", ERR_ERROR, "DB format error");
return;
}
while(dbfetchrow(dbres)) {
- unsigned long id;
+ unsigned long id, hitssaved;
+ time_t lastseen;
char *gline, *setby, *reason, *expires, *type, *class;
id = strtoul(dbgetvalue(dbres, 0), NULL, 10);
type = dbgetvalue(dbres, 5);
class = dbgetvalue(dbres, 6);
- if (!rg_newsstruct(id, gline, setby, reason, expires, type, 0, class))
- dbquery("DELETE FROM regexgline.glines WHERE id = %u", id);
+ lastseen = strtoul(dbgetvalue(dbres, 7), NULL, 10);
+ hitssaved = strtoul(dbgetvalue(dbres, 8), NULL, 10);
+
+ if (!rg_newsstruct(id, gline, setby, reason, expires, type, 0, class, lastseen, hitssaved))
+ dbquery("DELETE FROM regexgline.glines WHERE id = %lu", id);
}
dbclear(dbres);
"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();
rg_schedule = schedulerecurring(time(NULL) + 1, 0, 1, rg_checkexpiry, NULL);
+ schedulerecurring(time(NULL) + 60, 0, 60, rg_flush_schedule, NULL);
}
void rg_dbload(void) {
dbattach("regexgline");
- dbcreatequery("CREATE TABLE regexgline.glines (id INT NOT NULL PRIMARY KEY, gline TEXT NOT NULL, setby VARCHAR(%d) NOT NULL, reason VARCHAR(%d) NOT NULL, expires INT NOT NULL, type INT NOT NULL DEFAULT 1, class TEXT NOT NULL)", ACCOUNTLEN, RG_REASON_MAX);
+ dbcreatequery("CREATE TABLE regexgline.glines (id INT NOT NULL PRIMARY KEY, gline TEXT NOT NULL, setby VARCHAR(%d) NOT NULL, reason VARCHAR(%d) NOT NULL, expires INT NOT NULL, type INT NOT NULL DEFAULT 1, class TEXT NOT NULL, lastseen INT DEFAULT 0, hits INT DEFAULT 0)", ACCOUNTLEN, RG_REASON_MAX);
dbcreatequery("CREATE TABLE regexgline.clog (host VARCHAR(%d) NOT NULL, account VARCHAR(%d) NOT NULL, event TEXT NOT NULL, arg TEXT NOT NULL, ts TIMESTAMP)", RG_MASKLEN - 1, ACCOUNTLEN);
dbcreatequery("CREATE TABLE regexgline.glog (glineid INT NOT NULL, ts TIMESTAMP, nickname VARCHAR(%d) NOT NULL, username VARCHAR(%d) NOT NULL, hostname VARCHAR(%d) NOT NULL, realname VARCHAR(%d))", NICKLEN, USERLEN, HOSTLEN, REALLEN);
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);
+ if(ignorable_nick(np))
+ return;
hostlen = RGBuildHostname(hostname, np);
- if(IsOper(np) || IsService(np) || IsXOper(np))
- return;
-
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);
}
dbescapestring(eereason, reason, strlen(reason));
highestid = highestid + 1;
- dbquery("INSERT INTO regexgline.glines (id, gline, setby, reason, expires, type, class) VALUES (%d, '%s', '%s', '%s', %d, %c, '%s')", highestid, eemask, eesetby, eereason, realexpiry, type, eeclass);
- rp = rg_newsstruct(highestid, regex, np->nick, reason, "", cargv[2], realexpiry, class);
+ dbquery("INSERT INTO regexgline.glines (id, gline, setby, reason, expires, type, class, lastseen, hits) VALUES (%lu, '%s', '%s', '%s', %lu, %c, '%s', 0, 0)", highestid, eemask, eesetby, eereason, realexpiry, type, eeclass);
+ rp = rg_newsstruct(highestid, regex, np->nick, reason, "", cargv[2], realexpiry, class, 0, 0);
rg_initglinelist(&gll);
for(j=0;j<NICKHASHSIZE;j++) {
for(tnp=nicktable[j];tnp;tnp=tnp->next) {
- if(IsOper(tnp) || IsService(tnp) || IsXOper(tnp))
+ if(ignorable_nick(tnp))
continue;
hostlen = RGBuildHostname(hostname, tnp);
} else {
struct rg_struct *rp;
unsigned long id = 0;
- int i;
+ int i, longest = 0;
+ unsigned int m;
for(i=0;i<8;i++) {
if(0xff == rc_hexlookup[(int)cargv[0][i]]) {
}
}
- controlreply(np, "Mask Expires Set by Type Reason");
+ m = getrgmarker();
+ controlreply(np, GLINE_HEADER);
+ for(rp=rg_list;rp;rp=rp->next) {
+ if(id == rp->glineid) {
+ rp->marker = m;
+ if(rp->mask->length > longest)
+ longest = rp->mask->length;
+ }
+ }
+
for(rp=rg_list;rp;rp=rp->next)
- if(id == rp->glineid)
- rg_displaygline(np, rp);
+ if(rp->marker == m)
+ rg_displaygline(np, rp, longest);
controlreply(np, "Done.");
return CMD_OK;
int rg_glist(void *source, int cargc, char **cargv) {
nick *np = (nick *)source;
struct rg_struct *rp;
+ int longest = 0;
if(cargc) {
int erroroffset;
pcre *regex;
pcre_extra *hint;
const char *error;
-
+ unsigned int m;
+
if(!(regex = pcre_compile(cargv[0], RG_PCREFLAGS, &error, &erroroffset, NULL))) {
controlreply(np, "Error compiling expression %s at offset %d: %s", cargv[0], erroroffset, error);
return CMD_ERROR;
return CMD_ERROR;
}
}
-
+
+ m = getrgmarker();
rg_logevent(np, "regexglist", "%s", cargv[0]);
- controlreply(np, "Mask Expires Set by Class Type Hits Reason");
+ controlreply(np, GLINE_HEADER);
+ for(rp=rg_list;rp;rp=rp->next) {
+ if(pcre_exec(regex, hint, rp->mask->content, rp->mask->length, 0, 0, NULL, 0) >= 0) {
+ rp->marker = m;
+ if(rp->mask->length > longest)
+ longest = rp->mask->length;
+ }
+ }
+
for(rp=rg_list;rp;rp=rp->next)
- if(pcre_exec(regex, hint, rp->mask->content, rp->mask->length, 0, 0, NULL, 0) >= 0)
- rg_displaygline(np, rp);
-
+ if(rp->marker == m)
+ rg_displaygline(np, rp, longest);
+
pcre_free(regex);
if(hint)
pcre_free(hint);
} else {
- rg_logevent(np, "regexglist", "");
- controlreply(np, "Mask Expires Set by Class Type Hits Reason");
+ rg_logevent(np, "regexglist", "%s", "");
+ controlreply(np, GLINE_HEADER);
for(rp=rg_list;rp;rp=rp->next)
- rg_displaygline(np, rp);
+ if(rp->mask->length > longest)
+ longest = rp->mask->length;
+
+ for(rp=rg_list;rp;rp=rp->next)
+ rg_displaygline(np, rp, longest);
}
controlreply(np, "Done.");
return ctypebuf;
}
-void rg_displaygline(nick *np, struct rg_struct *rp) { /* could be a macro? I'll assume the C compiler inlines it */
- controlreply(np, " %-25s %-20s %-15s %-8s %-5s %-5lu %s", rp->mask->content, longtoduration(rp->expires - time(NULL), 0), rp->setby->content, rp->class, displaytype(rp->type), rp->hits, rp->reason->content);
+char *getsep(int longest) {
+ static int lastlongest = -1;
+ static char lenbuf[1024];
+
+ longest = 125;
+/*
+ if(longest < 100)
+ longest = 100;
+
+ if(longest >= sizeof(lenbuf) - 20)
+ longest = sizeof(lenbuf) - 20;
+*/
+ longest+=4;
+ if(lastlongest == -1) {
+ int i;
+
+ for(i=0;i<sizeof(lenbuf)-1;i++)
+ lenbuf[i] = '-';
+ lenbuf[sizeof(lenbuf)-1] = '\0';
+ lastlongest = 0;
+ }
+
+ if(lastlongest != longest) {
+ lenbuf[lastlongest] = '-';
+ lenbuf[longest] = '\0';
+ lastlongest = longest;
+ }
+
+ return lenbuf;
+}
+
+void rg_displaygline(nick *np, struct rg_struct *rp, int longest) { /* could be a macro? I'll assume the C compiler inlines it */
+ char *sep = getsep(longest);
+/* 12345678 12345678901234567890 123456789012345 12345678 12345 12345678901234567890 1234567 1234567 123456
+ ID Expires Set by Class Type Last seen (ago) Hits(s) Hits Reason
+*/
+
+ char d[512];
+ time_t t = time(NULL);
+
+ if(rp->lastseen == 0) {
+ strlcpy(d, "(never)", sizeof(d));
+ } else {
+ strlcpy(d, longtoduration(t - rp->lastseen, 2), sizeof(d));
+ }
+
+ controlreply(np, "%s", rp->mask->content);
+ controlreply(np, " %08lx %-20s %-15s %-8s %-5s %-20s %-7lu %-7lu %s", rp->glineid, longtoduration(rp->expires - t, 2), rp->setby->content, rp->class, displaytype(rp->type), d, rp->hitssaved, rp->hits, rp->reason->content);
+ controlreply(np, "%s", sep);
}
int rg_spew(void *source, int cargc, char **cargv) {
}
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(IsOper(np) || IsService(np) || IsXOper(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);
}
if(rp) {
struct rg_struct *tp, *lp;
- memset(rp, 0, sizeof(rp));
+ memset(rp, 0, sizeof(rg_struct));
rp->expires = expires;
for(lp=NULL,tp=rg_list;tp;lp=tp,tp=tp->next) {
return rp;
}
-struct rg_struct *rg_newsstruct(unsigned long id, char *mask, char *setby, char *reason, char *expires, char *type, time_t iexpires, char *class) {
+struct rg_struct *rg_newsstruct(unsigned long id, char *mask, char *setby, char *reason, char *expires, char *type, time_t iexpires, char *class, time_t lastseen, unsigned int hitssaved) {
struct rg_struct *newrow, *lp, *cp;
time_t rexpires;
char glineiddata[1024];
}
newrow->id = id;
+ newrow->hitssaved = hitssaved;
+ newrow->lastseen = lastseen;
newrow->mask = getsstring(mask, RG_REGEXGLINE_MAX);
if(!newrow->mask) {
}
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);
}
if (rp->type == INSTANT_IDENT_GLINE) {
- if (IsAccount(np)) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, np->authname, rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(np), rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
} else if(rp->type == INSTANT_HOST_GLINE) {
- if (IsAccount(np)) {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, np->authname, rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
- } else {
- controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
- }
+ controlwall(NO_OPER, NL_HITS, "%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(np), rp->glineid, rp->class, usercount, (usercount!=1)?"s":"");
} else {
return 0;
}
rg_shadowserver(np, rp, rp->type);
- irc_send("%s GL * +%s %d %d :AUTO: %s (ID: %08lx)\r\n", mynumeric->content, hostname, rg_expiry_time, 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;
}
+static char *gvhost(nick *np) {
+ static char buf[NICKLEN+1+USERLEN+1+HOSTLEN+1+ACCOUNTLEN+4+REALLEN+1+10];
+
+ if(IsAccount(np)) {
+ snprintf(buf, sizeof(buf), "%s!%s@%s/%s r(%s)", np->nick, np->ident, np->host->name->content, np->authname, np->realname->name->content);
+ } else {
+ snprintf(buf, sizeof(buf), "%s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content);
+ }
+
+ return buf;
+}
+
static int floodprotection = 0;
static int lastfloodspam = 0;
int masklen;
va_list va;
-
- va_start(va, details);
- vsnprintf(buf, sizeof(buf), details, va);
- va_end(va);
-
+
+ if(details) {
+ va_start(va, details);
+ vsnprintf(buf, sizeof(buf), details, va);
+ va_end(va);
+ } else {
+ buf[0] = '\0';
+ }
+
if(np) {
if (IsAccount(np)) {
strncpy(account, np->authname, sizeof(account) - 1);
char eenick[RG_QUERY_BUF_SIZE], eeuser[RG_QUERY_BUF_SIZE], eehost[RG_QUERY_BUF_SIZE], eereal[RG_QUERY_BUF_SIZE];
rg->hits++;
+ rg->hitssaved++;
+ rg->lastseen = time(NULL);
+ rg->dirty = 1;
/* @paul: disabled */
dbquery("INSERT INTO regexgline.glog (glineid, nickname, username, hostname, realname, ts) VALUES (%d, '%s', '%s', '%s', '%s', NOW())", rg->id, eenick, eeuser, eehost, eereal);
}
+
+static unsigned int getrgmarker(void) {
+ static unsigned int marker = 0;
+
+ marker++;
+ if(!marker) {
+ struct rg_struct *l;
+
+ /* If we wrapped to zero, zap the marker on all hosts */
+ for(l=rg_list;l;l=l->next)
+ l->marker=0;
+ marker++;
+ }
+
+ return marker;
+}
+
+void rg_flush_schedule(void *arg) {
+ struct rg_struct *l;
+
+ for(l=rg_list;l;l=l->next) {
+ if(!l->dirty)
+ continue;
+
+ dbquery("UPDATE regexgline.glines SET lastseen = %jd, hits = %lu WHERE id = %d", (intmax_t)l->lastseen, l->hitssaved, l->id);
+
+ l->dirty = 0;
+ }
+}
+