X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/0b2e8a55087f15655b242683f2083ff017bed630..3e1b768066a16c4b899b9cbdd7911be883151a05:/glines/glines_buf.c diff --git a/glines/glines_buf.c b/glines/glines_buf.c index b76ad178..01b85c6b 100644 --- a/glines/glines_buf.c +++ b/glines/glines_buf.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include "../lib/array.h" #include "../lib/irc_string.h" #include "../irc/irc.h" #include "../control/control.h" @@ -11,15 +13,20 @@ static int nextglinebufid = 1; glinebuf *glinebuflog[MAXGLINELOG] = {}; int glinebuflogoffset = 0; -void glinebufinit(glinebuf *gbuf, int merge) { - gbuf->id = 0; +void glinebufinit(glinebuf *gbuf, int id) { + gbuf->id = id; gbuf->comment = NULL; + gbuf->commit = 0; + gbuf->amend = 0; gbuf->glines = NULL; - gbuf->merge = merge; + gbuf->hitsvalid = 1; + gbuf->userhits = 0; + gbuf->channelhits = 0; + array_init(&gbuf->hits, sizeof(sstring *)); } gline *glinebufadd(glinebuf *gbuf, const char *mask, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { - gline *gl, *sgl, **pnext; + gline *gl; gl = makegline(mask); /* sets up nick,user,host,node and flags */ @@ -29,29 +36,6 @@ gline *glinebufadd(glinebuf *gbuf, const char *mask, const char *creator, const return 0; } - if (gbuf->merge) { - /* Check if an existing gline supercedes this mask */ - for (sgl = gbuf->glines; sgl; sgl = sgl->next) { - if (gline_match_mask(sgl, gl)) { - freegline(gl); - return sgl; - } - } - - /* Remove older glines this gline matches */ - for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) { - sgl = *pnext; - - if (gline_match_mask(gl, sgl)) { - *pnext = sgl->next; - freegline(sgl); - - if (!*pnext) - break; - } - } - } - gl->creator = getsstring(creator, 255); /* it's not unreasonable to assume gline is active, if we're adding a deactivated gline, we can remove this later */ @@ -65,12 +49,14 @@ gline *glinebufadd(glinebuf *gbuf, const char *mask, const char *creator, const gl->next = gbuf->glines; gbuf->glines = gl; + gbuf->hitsvalid = 0; + return gl; } -void glinebufaddbyip(glinebuf *gbuf, const char *user, struct irc_in_addr *ip, unsigned char bits, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { +char *glinebufaddbyip(glinebuf *gbuf, const char *user, struct irc_in_addr *ip, unsigned char bits, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { trusthost *th, *oth; - char mask[512]; + static char mask[512]; unsigned char nodebits; nodebits = getnodebits(ip); @@ -82,7 +68,8 @@ void glinebufaddbyip(glinebuf *gbuf, const char *user, struct irc_in_addr *ip, u for (oth = th->group->hosts; oth; oth = oth->next) glinebufaddbyip(gbuf, user, &oth->ip, oth->bits, flags | GLINE_ALWAYS_USER | GLINE_IGNORE_TRUST, creator, reason, expire, lastmod, lifetime); - return; + snprintf(mask, sizeof(mask), "%s@%s/tg%u", user, (bits == 128) ? IPtostr(*ip) : CIDRtostr(*ip, bits), th->group->id); + return mask; } } @@ -93,90 +80,122 @@ void glinebufaddbyip(glinebuf *gbuf, const char *user, struct irc_in_addr *ip, u if (nodebits < bits) bits = nodebits; - snprintf(mask, sizeof(mask), "%s@%s", user, trusts_cidr2str(ip, bits)); + snprintf(mask, sizeof(mask), "%s@%s", user, (bits == 128) ? IPtostr(*ip) : CIDRtostr(*ip, bits)); glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime); + return mask; +} + +char *glinebufaddbynick(glinebuf *gbuf, nick *np, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { + if (flags & GLINE_ALWAYS_NICK) { + static char mask[512]; + snprintf(mask, sizeof(mask), "%s!*@*", np->nick); + glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime); + return mask; + } else { + return glinebufaddbyip(gbuf, np->ident, &np->ipaddress, 128, flags, creator, reason, expire, lastmod, lifetime); + } } -void glinebufaddbynick(glinebuf *gbuf, nick *np, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { +void glinebufaddbywhowas(glinebuf *gbuf, whowas *ww, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) { + nick *np = &ww->nick; + if (flags & GLINE_ALWAYS_NICK) { char mask[512]; snprintf(mask, sizeof(mask), "%s!*@*", np->nick); glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime); } else { - glinebufaddbyip(gbuf, np->ident, &np->p_ipaddr, 128, flags, creator, reason, expire, lastmod, lifetime); + glinebufaddbyip(gbuf, np->ident, &np->ipaddress, 128, flags, creator, reason, expire, lastmod, lifetime); } } -void glinebufcounthits(glinebuf *gbuf, int *users, int *channels, nick *spewto) { +void glinebufcounthits(glinebuf *gbuf, int *users, int *channels) { gline *gl; - int i, hit; + int i, hit, slot; chanindex *cip; channel *cp; nick *np; + char uhmask[512]; - if (users) - *users = 0; +#if 0 /* Let's just do a new hit check anyway. */ + if (gbuf->hitsvalid) + return; +#endif - if (channels) - *channels = 0; + gbuf->userhits = 0; + gbuf->channelhits = 0; - if (channels) { - for (i = 0; inext) { - cp = cip->channel; + for (i = 0; i < gbuf->hits.cursi; i++) + freesstring(((sstring **)gbuf->hits.content)[i]); - if (!cp) - continue; + array_free(&gbuf->hits); + array_init(&gbuf->hits, sizeof(sstring *)); - hit = 0; + for (i = 0; inext) { + cp = cip->channel; - for (gl = gbuf->glines; gl; gl = gl->next) { - if (gline_match_channel(gl, cp)) { - hit = 1; - break; - } - } + if (!cp) + continue; - if (hit) { - if (spewto) - controlreply(spewto, "channel: %s", cip->name->content); + hit = 0; - (*channels)++; + for (gl = gbuf->glines; gl; gl = gl->next) { + if (gline_match_channel(gl, cp)) { + hit = 1; + break; } } + + if (hit) { + snprintf(uhmask, sizeof(uhmask), "channel: %s", cip->name->content); + + gbuf->channelhits++; + + slot = array_getfreeslot(&gbuf->hits); + ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512); + } } } - if (users) { - for (i = 0; i < NICKHASHSIZE; i++) { - for (np = nicktable[i]; np; np = np->next) { - hit = 0; + for (i = 0; i < NICKHASHSIZE; i++) { + for (np = nicktable[i]; np; np = np->next) { + hit = 0; - for (gl = gbuf->glines; gl; gl = gl->next) { - if (gline_match_nick(gl, np)) { - hit = 1; - break; - } + for (gl = gbuf->glines; gl; gl = gl->next) { + if (gline_match_nick(gl, np)) { + hit = 1; + break; } + } - if (hit) { - if (spewto) - controlreply(spewto, "user: %s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content); + if (hit) { + snprintf(uhmask, sizeof(uhmask), "user: %s!%s@%s%s%s r(%s)", np->nick, np->ident, np->host->name->content, + (np->auth) ? "/" : "", (np->auth) ? np->authname : "", np->realname->name->content); - (*users)++; - } + gbuf->userhits++; + + slot = array_getfreeslot(&gbuf->hits); + ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512); } } } + + gbuf->hitsvalid = 1; + + if (users) + *users = gbuf->userhits; + + if (channels) + *channels = gbuf->channelhits; } -int glinebufchecksane(glinebuf *gbuf, nick *spewto, int overridesanity, int overridelimit, int spewhits) { +int glinebufchecksane(glinebuf *gbuf, nick *spewto, int overridesanity, int overridelimit) { gline *gl; int users, channels, good; const char *hint; - glinebufcounthits(gbuf, &users, &channels, spewhits ? spewto : NULL); + glinebufcounthits(gbuf, &users, &channels); if (!overridelimit) { if (channels > MAXUSERGLINECHANNELHITS) { @@ -206,42 +225,105 @@ int glinebufchecksane(glinebuf *gbuf, nick *spewto, int overridesanity, int over void glinebufspew(glinebuf *gbuf, nick *spewto) { gline *gl; - time_t ref; - - ref = (gbuf->flush) ? gbuf->flush : getnettime(); + int i; + char timebuf[30], lastmod[30]; + + if (!gbuf->hitsvalid) + glinebufcounthits(gbuf, NULL, NULL); + + if (gbuf->id == 0) + controlreply(spewto, "Uncommitted G-Line transaction."); + else + controlreply(spewto, "G-Line transaction ID %d", gbuf->id); + + controlreply(spewto, "Comment: %s", (gbuf->comment) ? gbuf->comment->content : "(no comment)"); + + if (gbuf->commit) { + strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gbuf->commit)); + controlreply(spewto, "Committed at: %s", timebuf); + } - controlreply(spewto, "Mask Duration Creator Reason"); + if (gbuf->amend) { + strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gbuf->amend)); + controlreply(spewto, "Amended at: %s", timebuf); + } + + controlreply(spewto, "Mask Expiry Last modified Creator Reason"); - for (gl = gbuf->glines; gl; gl = gl->next) - controlreply(spewto, "%-40s %-20s %-20s %s", glinetostring(gl), longtoduration(gl->expire - ref, 0), gl->creator->content, gl->reason->content); + for (gl = gbuf->glines; gl; gl = gl->next) { + strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gl->expire)); + + if (gl->lastmod == 0) + strncpy(lastmod, "", sizeof(lastmod)); + else + strftime(lastmod, sizeof(lastmod), "%d/%m/%y %H:%M:%S", localtime(&gl->lastmod)); + + controlreply(spewto, "%-40s %-20s %-20s %-25s %s", glinetostring(gl), timebuf, lastmod, gl->creator->content, gl->reason ? gl->reason->content : ""); + } + + controlreply(spewto, "Hits"); + + for (i = 0; i < gbuf->hits.cursi; i++) { + controlreply(spewto, "%s", ((sstring **)gbuf->hits.content)[i]->content); + + if (i >= 500) { + controlreply(spewto, "More than 500 hits, list truncated."); + break; + } + } + + if (i == 0) + controlreply(spewto, "(no hits)"); } -void glinebufcommit(glinebuf *gbuf, int propagate) { +void glinebufmerge(glinebuf *gbuf) { + /* TODO: reimplement */ + +/* + if (gbuf->merge) { + /-* Check if an existing gline supercedes this mask *-/ + for (sgl = gbuf->glines; sgl; sgl = sgl->next) { + if (gline_match_mask(sgl, gl)) { + freegline(gl); + return sgl; + } + } + + /-* Remove older glines this gline matches *-/ + for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) { + sgl = *pnext; + + if (gline_match_mask(gl, sgl)) { + *pnext = sgl->next; + freegline(sgl); + + if (!*pnext) + break; + } + } + } +*/ +} + +int glinebufcommit(glinebuf *gbuf, int propagate) { gline *gl, *next, *sgl; - glinebuf *gbl; - int users, channels; + int users, channels, id; /* Sanity check */ - glinebufcounthits(gbuf, &users, &channels, NULL); + glinebufcounthits(gbuf, &users, &channels); if (propagate && (users > MAXGLINEUSERHITS || channels > MAXGLINECHANNELHITS)) { - controlwall(NO_OPER, NL_GLINES, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines."); + controlwall(NO_OPER, NL_GLINES_AUTO, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines."); glinebufabort(gbuf); - return; + return 0; } - time(&gbuf->flush); + /* Record the commit time */ + time(&gbuf->commit); - if (propagate) { - /* Make a copy of the glinebuf for the log */ - gbl = malloc(sizeof(glinebuf)); - gbl->id = nextglinebufid++; - gbl->comment = (gbuf->comment) ? getsstring(gbuf->comment->content, 512) : NULL; - gbl->flush = gbuf->flush; - gbl->glines = NULL; /* going to set this later */ - gbl->merge = gbuf->merge; - } + id = glinebufwritelog(gbuf, propagate); + /* Move glines to the global gline list */ for (gl = gbuf->glines; gl; gl = next) { next = gl->next; @@ -274,32 +356,23 @@ void glinebufcommit(glinebuf *gbuf, int propagate) { glinelist = gl; } - if (propagate) { - gline_propagate(gl); + gl->glinebufid = id; - sgl = glinedup(gl); - sgl->next = gbl->glines; - gbl->glines = sgl; - } + if (propagate) + gline_propagate(gl); } - if (propagate && gbl->glines) { - glinebuflogoffset++; - - if (glinebuflogoffset >= MAXGLINELOG) - glinebuflogoffset = 0; - - if (glinebuflog[glinebuflogoffset]) - glinebufabort(glinebuflog[glinebuflogoffset]); + /* We've moved all glines to the global gline list. Clear glines link in the glinebuf. */ + gbuf->glines = NULL; - glinebuflog[glinebuflogoffset]= gbl; - } - glinebufabort(gbuf); + + return id; } void glinebufabort(glinebuf *gbuf) { gline *gl, *next; + int i; for (gl = gbuf->glines; gl; gl = next) { next = gl->next; @@ -308,6 +381,11 @@ void glinebufabort(glinebuf *gbuf) { } freesstring(gbuf->comment); + + for (i = 0; i < gbuf->hits.cursi; i++) + freesstring(((sstring **)gbuf->hits.content)[i]); + + array_free(&gbuf->hits); } int glinebufundo(int id) { @@ -326,7 +404,9 @@ int glinebufundo(int id) { if (!sgl) continue; - + + sgl->glinebufid = 0; + gline_deactivate(sgl, 0, 1); } @@ -371,3 +451,101 @@ void glinebufcommentv(glinebuf *gbuf, const char *prefix, int cargc, char **carg gbuf->comment = getsstring(comment, 512); } + +int glinebufwritelog(glinebuf *gbuf, int propagating) { + int i, slot; + gline *gl, *sgl; + glinebuf *gbl; + + if (!gbuf->glines) + return 0; /* Don't waste log IDs on empty gline buffers */ + + gbl = NULL; + + /* Find an existing log buffer with the same id */ + if (gbuf->id != 0) { + for (i = 0; i < MAXGLINELOG; i++) { + if (!glinebuflog[i]) + continue; + + if (glinebuflog[i]->id == gbuf->id) { + gbl = glinebuflog[i]; + gbl->amend = gbuf->commit; + + /* We're going to re-insert this glinebuf, so remove it for now */ + glinebuflog[i] = NULL; + + break; + } + } + } + + /* Find a recent glinebuf that's a close match */ + if (!gbl && !propagating) { + for (i = 0; i < MAXGLINELOG; i++) { + if (!glinebuflog[i]) + continue; + + if (glinebuflog[i]->commit < getnettime() - 5 && glinebuflog[i]->amend < getnettime() - 5) + continue; + + assert(glinebuflog[i]->glines); + + if (strcmp(glinebuflog[i]->glines->creator->content, gbuf->glines->creator->content) != 0) + continue; + + gbl = glinebuflog[i]; + gbl->amend = gbuf->commit; + + /* We're going to re-insert this glinebuf, so remove it for now */ + glinebuflog[i] = NULL; + + break; + } + } + + /* Make a new glinebuf for the log */ + if (!gbl) { + gbl = malloc(sizeof(glinebuf)); + glinebufinit(gbl, (gbuf->id == 0) ? nextglinebufid++ : gbuf->id); + + assert(gbl->hitsvalid); + + if (gbuf->comment) + glinebufcommentf(gbl, "%s", gbuf->comment->content); + else if (!propagating) + glinebufcommentf(gbl, "G-Lines set by %s", gbuf->glines->creator->content); + + gbl->commit = gbuf->commit; + } + + /* Save a duplicate of the glines in the log buffer */ + for (gl = gbuf->glines; gl; gl = gl->next) { + sgl = glinedup(gl); + sgl->next = gbl->glines; + gbl->glines = sgl; + } + + gbl->userhits += gbuf->userhits; + gbl->channelhits += gbuf->channelhits; + + assert(gbuf->userhits + gbuf->channelhits == gbuf->hits.cursi); + + for (i = 0; i < gbuf->hits.cursi; i++) { + slot = array_getfreeslot(&gbl->hits); + ((sstring **)gbl->hits.content)[slot] = getsstring(((sstring **)gbuf->hits.content)[i]->content, 512); + } + + /* Log the transaction */ + glinebuflogoffset++; + + if (glinebuflogoffset >= MAXGLINELOG) + glinebuflogoffset = 0; + + if (glinebuflog[glinebuflogoffset]) + glinebufabort(glinebuflog[glinebuflogoffset]); + + glinebuflog[glinebuflogoffset] = gbl; + + return gbl->id; +}