]> jfr.im git - irc/quakenet/newserv.git/blob - glines/glines_buf.c
glinelog: Keep track of hits.
[irc/quakenet/newserv.git] / glines / glines_buf.c
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "../lib/array.h"
5 #include "../lib/irc_string.h"
6 #include "../irc/irc.h"
7 #include "../control/control.h"
8 #include "../trusts/trusts.h"
9 #include "glines.h"
10
11 static int nextglinebufid = 1;
12 glinebuf *glinebuflog[MAXGLINELOG] = {};
13 int glinebuflogoffset = 0;
14
15 void glinebufinit(glinebuf *gbuf, int merge) {
16 gbuf->id = 0;
17 gbuf->comment = NULL;
18 gbuf->glines = NULL;
19 gbuf->merge = merge;
20 gbuf->userhits = 0;
21 gbuf->channelhits = 0;
22 array_init(&gbuf->hits, sizeof(sstring *));
23 }
24
25 gline *glinebufadd(glinebuf *gbuf, const char *mask, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) {
26 gline *gl, *sgl, **pnext;
27
28 gl = makegline(mask); /* sets up nick,user,host,node and flags */
29
30 if (!gl) {
31 /* couldn't process gline mask */
32 Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask);
33 return 0;
34 }
35
36 if (gbuf->merge) {
37 /* Check if an existing gline supercedes this mask */
38 for (sgl = gbuf->glines; sgl; sgl = sgl->next) {
39 if (gline_match_mask(sgl, gl)) {
40 freegline(gl);
41 return sgl;
42 }
43 }
44
45 /* Remove older glines this gline matches */
46 for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) {
47 sgl = *pnext;
48
49 if (gline_match_mask(gl, sgl)) {
50 *pnext = sgl->next;
51 freegline(sgl);
52
53 if (!*pnext)
54 break;
55 }
56 }
57 }
58
59 gl->creator = getsstring(creator, 255);
60
61 /* it's not unreasonable to assume gline is active, if we're adding a deactivated gline, we can remove this later */
62 gl->flags |= GLINE_ACTIVE;
63
64 gl->reason = getsstring(reason, 255);
65 gl->expire = expire;
66 gl->lastmod = lastmod;
67 gl->lifetime = lifetime;
68
69 gl->next = gbuf->glines;
70 gbuf->glines = gl;
71
72 return gl;
73 }
74
75 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) {
76 trusthost *th, *oth;
77 char mask[512];
78 unsigned char nodebits;
79
80 nodebits = getnodebits(ip);
81
82 if (!(flags & GLINE_IGNORE_TRUST)) {
83 th = th_getbyhost(ip);
84
85 if (th && (th->group->flags & TRUST_RELIABLE_USERNAME)) { /* Trust with reliable usernames */
86 for (oth = th->group->hosts; oth; oth = oth->next)
87 glinebufaddbyip(gbuf, user, &oth->ip, oth->bits, flags | GLINE_ALWAYS_USER | GLINE_IGNORE_TRUST, creator, reason, expire, lastmod, lifetime);
88
89 return;
90 }
91 }
92
93 if (!(flags & GLINE_ALWAYS_USER))
94 user = "*";
95
96 /* Widen gline to match the node mask. */
97 if (nodebits < bits)
98 bits = nodebits;
99
100 snprintf(mask, sizeof(mask), "%s@%s", user, trusts_cidr2str(ip, bits));
101
102 glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime);
103 }
104
105 void glinebufaddbynick(glinebuf *gbuf, nick *np, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) {
106 if (flags & GLINE_ALWAYS_NICK) {
107 char mask[512];
108 snprintf(mask, sizeof(mask), "%s!*@*", np->nick);
109 glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime);
110 } else {
111 glinebufaddbyip(gbuf, np->ident, &np->p_ipaddr, 128, flags, creator, reason, expire, lastmod, lifetime);
112 }
113 }
114
115 void glinebufcounthits(glinebuf *gbuf, int *users, int *channels, nick *spewto) {
116 gline *gl;
117 int i, hit, slot;
118 chanindex *cip;
119 channel *cp;
120 nick *np;
121 char uhmask[512];
122
123 gbuf->userhits = 0;
124 gbuf->channelhits = 0;
125
126 for (i = 0; i < gbuf->hits.cursi; i++)
127 freesstring(((sstring **)gbuf->hits.content)[i]);
128
129 array_free(&gbuf->hits);
130 array_init(&gbuf->hits, sizeof(sstring *));
131
132 for (i = 0; i<CHANNELHASHSIZE; i++) {
133 for (cip = chantable[i]; cip; cip = cip->next) {
134 cp = cip->channel;
135
136 if (!cp)
137 continue;
138
139 hit = 0;
140
141 for (gl = gbuf->glines; gl; gl = gl->next) {
142 if (gline_match_channel(gl, cp)) {
143 hit = 1;
144 break;
145 }
146 }
147
148 if (hit) {
149 snprintf(uhmask, sizeof(uhmask), "channel: %s", cip->name->content);
150
151 if (spewto)
152 controlreply(spewto, "%s", uhmask);
153
154 gbuf->channelhits++;
155
156 slot = array_getfreeslot(&gbuf->hits);
157 ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512);
158 }
159 }
160 }
161
162 for (i = 0; i < NICKHASHSIZE; i++) {
163 for (np = nicktable[i]; np; np = np->next) {
164 hit = 0;
165
166 for (gl = gbuf->glines; gl; gl = gl->next) {
167 if (gline_match_nick(gl, np)) {
168 hit = 1;
169 break;
170 }
171 }
172
173 if (hit) {
174 snprintf(uhmask, sizeof(uhmask), "user: %s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content);
175
176 if (spewto)
177 controlreply(spewto, "%s", uhmask);
178
179 gbuf->userhits++;
180
181 slot = array_getfreeslot(&gbuf->hits);
182 ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512);
183 }
184 }
185 }
186
187 if (users)
188 *users = gbuf->userhits;
189
190 if (channels)
191 *channels = gbuf->channelhits;
192 }
193
194 int glinebufchecksane(glinebuf *gbuf, nick *spewto, int overridesanity, int overridelimit, int spewhits) {
195 gline *gl;
196 int users, channels, good;
197 const char *hint;
198
199 glinebufcounthits(gbuf, &users, &channels, spewhits ? spewto : NULL);
200
201 if (!overridelimit) {
202 if (channels > MAXUSERGLINECHANNELHITS) {
203 controlreply(spewto, "G-Lines would hit %d channels. Limit is %d. Not setting G-Lines.", channels, MAXUSERGLINECHANNELHITS);
204 return 0;
205 } else if (users > MAXUSERGLINEUSERHITS) {
206 controlreply(spewto, "G-Lines would hit %d users. Limit is %d. Not setting G-Lines.", users, MAXUSERGLINEUSERHITS);
207 return 0;
208 }
209 }
210
211 good = 1;
212
213 if (!overridesanity) {
214 /* Remove glines that fail the sanity check */
215 for (gl = gbuf->glines; gl; gl = gl->next) {
216 if (!isglinesane(gl, &hint)) {
217 controlreply(spewto, "Sanity check failed for G-Line on '%s' - Skipping: %s",
218 glinetostring(gl), hint);
219 good = 0;
220 }
221 }
222 }
223
224 return good;
225 }
226
227 void glinebufspew(glinebuf *gbuf, nick *spewto) {
228 gline *gl;
229 time_t ref;
230 int i;
231
232 ref = (gbuf->flush) ? gbuf->flush : getnettime();
233
234 controlreply(spewto, "Mask Duration Creator Reason");
235
236 for (gl = gbuf->glines; gl; gl = gl->next)
237 controlreply(spewto, "%-40s %-20s %-20s %s", glinetostring(gl), longtoduration(gl->expire - ref, 0), gl->creator->content, gl->reason->content);
238
239 controlreply(spewto, "Hit");
240
241 for (i = 0; i < gbuf->hits.cursi; i++)
242 controlreply(spewto, "%s", ((sstring **)gbuf->hits.content)[i]->content);
243 }
244
245 void glinebufcommit(glinebuf *gbuf, int propagate) {
246 gline *gl, *next, *sgl;
247 glinebuf *gbl;
248 int users, channels, i, slot;
249
250 /* Sanity check */
251 glinebufcounthits(gbuf, &users, &channels, NULL);
252
253 if (propagate && (users > MAXGLINEUSERHITS || channels > MAXGLINECHANNELHITS)) {
254 controlwall(NO_OPER, NL_GLINES, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines.");
255 glinebufabort(gbuf);
256 return;
257 }
258
259 time(&gbuf->flush);
260
261 if (propagate) {
262 /* Make a copy of the glinebuf for the log */
263 gbl = malloc(sizeof(glinebuf));
264 gbl->id = nextglinebufid++;
265 gbl->comment = (gbuf->comment) ? getsstring(gbuf->comment->content, 512) : NULL;
266 gbl->flush = gbuf->flush;
267 gbl->merge = gbuf->merge;
268 gbl->glines = NULL; /* going to set this later */
269 gbl->userhits = gbuf->userhits;
270 gbl->channelhits = gbuf->channelhits;
271
272 array_init(&gbl->hits, sizeof(sstring *));
273
274 for (i = 0; i < gbuf->hits.cursi; i++) {
275 slot = array_getfreeslot(&gbl->hits);
276 ((sstring **)gbl->hits.content)[slot] = getsstring(((sstring **)gbuf->hits.content)[i]->content, 512);
277 }
278 }
279
280 for (gl = gbuf->glines; gl; gl = next) {
281 next = gl->next;
282
283 sgl = findgline(glinetostring(gl));
284
285 if (sgl) {
286 /* existing gline
287 * in 1.4, can update expire, reason etc
288 * in 1.3 can only activate/deactivate an existing gline */
289
290 if (gl->flags & GLINE_ACTIVE && !(sgl->flags & GLINE_ACTIVE))
291 gline_activate(sgl, 0, 0);
292 else if (!(gl->flags & GLINE_ACTIVE) && sgl->flags & GLINE_ACTIVE)
293 gline_deactivate(sgl, 0, 0);
294
295 #if SNIRCD_VERSION >= 140
296 sgl->expire = gl->expire;
297
298 if (gl->lifetime > sgl->lifetime)
299 sgl->lifetime = gl->lifetime;
300
301 freesstring(sgl->reason);
302 sgl->reason = getsstring(gl->reason, 512);
303 #endif
304
305 freegline(gl);
306 gl = sgl;
307 } else {
308 gl->next = glinelist;
309 glinelist = gl;
310 }
311
312 if (propagate) {
313 gline_propagate(gl);
314
315 sgl = glinedup(gl);
316 sgl->next = gbl->glines;
317 gbl->glines = sgl;
318 }
319 }
320
321 /* We've moved all glines to the gline list. Clear glines link in the glinebuf. */
322 gbuf->glines = NULL;
323
324 if (propagate && gbl->glines) {
325 glinebuflogoffset++;
326
327 if (glinebuflogoffset >= MAXGLINELOG)
328 glinebuflogoffset = 0;
329
330 if (glinebuflog[glinebuflogoffset])
331 glinebufabort(glinebuflog[glinebuflogoffset]);
332
333 glinebuflog[glinebuflogoffset]= gbl;
334 }
335
336 glinebufabort(gbuf);
337 }
338
339 void glinebufabort(glinebuf *gbuf) {
340 gline *gl, *next;
341 int i;
342
343 for (gl = gbuf->glines; gl; gl = next) {
344 next = gl->next;
345
346 freegline(gl);
347 }
348
349 freesstring(gbuf->comment);
350
351 for (i = 0; i < gbuf->hits.cursi; i++)
352 freesstring(((sstring **)gbuf->hits.content)[i]);
353
354 array_free(&gbuf->hits);
355 }
356
357 int glinebufundo(int id) {
358 glinebuf *gbl;
359 gline *gl, *sgl;
360 int i;
361
362 for (i = 0; i < MAXGLINELOG; i++) {
363 gbl = glinebuflog[i];
364
365 if (!gbl || gbl->id != id)
366 continue;
367
368 for (gl = gbl->glines; gl; gl = gl->next) {
369 sgl = findgline(glinetostring(gl));
370
371 if (!sgl)
372 continue;
373
374 gline_deactivate(sgl, 0, 1);
375 }
376
377 glinebufabort(gbl);
378 glinebuflog[i] = NULL;
379
380 return 1;
381 }
382
383 return 0;
384 }
385
386 void glinebufcommentf(glinebuf *gbuf, const char *format, ...) {
387 char comment[512];
388 va_list va;
389
390 va_start(va, format);
391 vsnprintf(comment, 511, format, va);
392 comment[511] = '\0';
393 va_end(va);
394
395 gbuf->comment = getsstring(comment, 512);
396 }
397
398 void glinebufcommentv(glinebuf *gbuf, const char *prefix, int cargc, char **cargv) {
399 char comment[512];
400 int i;
401
402 if (prefix)
403 strncpy(comment, prefix, sizeof(comment));
404 else
405 comment[0] = '\0';
406
407 for (i = 0; i < cargc; i++) {
408 if (comment[0])
409 strncat(comment, " ", sizeof(comment));
410
411 strncat(comment, cargv[i], sizeof(comment));
412 }
413
414 comment[511] = '\0';
415
416 gbuf->comment = getsstring(comment, 512);
417 }