]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/data.c
Merge.
[irc/quakenet/newserv.git] / trusts / data.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4
5 #include "../lib/sstring.h"
6 #include "../core/hooks.h"
7 #include "../core/nsmalloc.h"
8 #include "../lib/irc_string.h"
9 #include "trusts.h"
10
11 trustgroup *tglist;
12
13 void th_dbupdatecounts(trusthost *);
14 void tg_dbupdatecounts(trustgroup *);
15
16 static trusthost *th_getnextchildbyhost(trusthost *, trusthost *);
17
18 void trusts_freeall(void) {
19 trustgroup *tg, *ntg;
20 trusthost *th, *nth;
21
22 for(tg=tglist;tg;tg=ntg) {
23 ntg = tg->next;
24 for(th=tg->hosts;th;th=nth) {
25 nth = th->next;
26
27 th_free(th);
28 }
29
30 tg_free(tg);
31 }
32
33 tglist = NULL;
34 }
35
36 trustgroup *tg_getbyid(unsigned int id) {
37 trustgroup *tg;
38
39 for(tg=tglist;tg;tg=tg->next)
40 if(tg->id == id)
41 return tg;
42
43 return NULL;
44 }
45
46 void th_free(trusthost *th) {
47 nsfree(POOL_TRUSTS, th);
48 }
49
50 static void th_updatechildren(trusthost *th) {
51 trusthost *nth = NULL;
52
53 th->children = NULL;
54
55 for(;;) {
56 nth = th_getnextchildbyhost(th, nth);
57 if(!nth)
58 break;
59
60 nth->nextbychild = th->children;
61 th->children = nth;
62 }
63 }
64
65 void th_linktree(void) {
66 trustgroup *tg;
67 trusthost *th;
68
69 /* ugh */
70 for(tg=tglist;tg;tg=tg->next)
71 for(th=tg->hosts;th;th=th->next)
72 th->parent = th_getsmallestsupersetbyhost(th->ip, th->mask);
73
74 for(tg=tglist;tg;tg=tg->next)
75 for(th=tg->hosts;th;th=th->next)
76 if(th->parent)
77 th_updatechildren(th->parent);
78 }
79
80 trusthost *th_add(trusthost *ith) {
81 trusthost *th;
82
83 th = nsmalloc(POOL_TRUSTS, sizeof(trusthost));
84 if(!th)
85 return NULL;
86
87 memcpy(th, ith, sizeof(trusthost));
88
89 th->users = NULL;
90 th->count = 0;
91
92 th->parent = NULL;
93 th->children = NULL;
94
95 th->marker = 0;
96
97 th->next = th->group->hosts;
98 th->group->hosts = th;
99
100 return th;
101 }
102
103 void tg_free(trustgroup *tg) {
104 triggerhook(HOOK_TRUSTS_LOSTGROUP, tg);
105
106 freesstring(tg->name);
107 freesstring(tg->createdby);
108 freesstring(tg->contact);
109 freesstring(tg->comment);
110 nsfree(POOL_TRUSTS, tg);
111 }
112
113 trustgroup *tg_add(trustgroup *itg) {
114 trustgroup *tg = nsmalloc(POOL_TRUSTS, sizeof(trustgroup));
115 if(!tg)
116 return NULL;
117
118 memcpy(tg, itg, sizeof(trustgroup));
119
120 tg->name = getsstring(tg->name->content, TRUSTNAMELEN);
121 tg->createdby = getsstring(tg->createdby->content, NICKLEN);
122 tg->contact = getsstring(tg->contact->content, CONTACTLEN);
123 tg->comment = getsstring(tg->comment->content, COMMENTLEN);
124 if(!tg->name || !tg->createdby || !tg->contact || !tg->comment) {
125 tg_free(tg);
126 return NULL;
127 }
128
129 tg->hosts = NULL;
130 tg->marker = 0;
131 tg->count = 0;
132
133 memset(tg->exts, 0, sizeof(tg->exts));
134
135 tg->next = tglist;
136 tglist = tg;
137
138 triggerhook(HOOK_TRUSTS_NEWGROUP, tg);
139
140 return tg;
141 }
142
143 trusthost *th_getbyhost(uint32_t ip) {
144 trustgroup *tg;
145 trusthost *th, *result = NULL;
146 uint32_t mask;
147
148 for(tg=tglist;tg;tg=tg->next) {
149 for(th=tg->hosts;th;th=th->next) {
150 if((ip & th->mask) == th->ip) {
151 if(!result || (th->mask > mask)) {
152 mask = th->mask;
153 result = th;
154 }
155 }
156 }
157 }
158
159 return result;
160 }
161
162 trusthost *th_getbyhostandmask(uint32_t ip, uint32_t mask) {
163 trustgroup *tg;
164 trusthost *th;
165
166 for(tg=tglist;tg;tg=tg->next)
167 for(th=tg->hosts;th;th=th->next)
168 if((th->ip == ip) && (th->mask == mask))
169 return th;
170
171 return NULL;
172 }
173
174 /* returns the ip with the smallest prefix that is still a superset of the given host */
175 trusthost *th_getsmallestsupersetbyhost(uint32_t ip, uint32_t mask) {
176 trustgroup *tg;
177 trusthost *th, *result = NULL;
178 uint32_t smask;
179
180 for(tg=tglist;tg;tg=tg->next) {
181 for(th=tg->hosts;th;th=th->next) {
182 if(th->ip == (ip & th->mask)) {
183 if((th->mask < mask) && (!result || (th->mask > smask))) {
184 smask = th->mask;
185 result = th;
186 }
187 }
188 }
189 }
190
191 return result;
192 }
193
194 /* returns the first ip that is a subset it comes across */
195 trusthost *th_getsubsetbyhost(uint32_t ip, uint32_t mask) {
196 trustgroup *tg;
197 trusthost *th;
198
199 for(tg=tglist;tg;tg=tg->next)
200 for(th=tg->hosts;th;th=th->next)
201 if((th->ip & mask) == ip)
202 if(th->mask > mask)
203 return th;
204
205 return NULL;
206 }
207
208 /* NOT reentrant obviously */
209 static trusthost *th_getnextchildbyhost(trusthost *orig, trusthost *th) {
210 if(!th) {
211 trustgroup *tg;
212
213 tg = tglist;
214 for(tg=tglist;tg;tg=tg->next) {
215 th = tg->hosts;
216 if(th)
217 break;
218 }
219
220 /* INVARIANT: tg => th */
221 if(!tg)
222 return NULL;
223
224 if(th->parent == orig)
225 return th;
226 }
227
228 for(;;) {
229 if(th->next) {
230 th = th->next;
231 } else {
232 if(!th->group->next)
233 return NULL;
234 th = th->group->next->hosts;
235 }
236
237 if(th->parent == orig)
238 return th;
239 }
240 }
241
242 void th_getsuperandsubsets(uint32_t ip, uint32_t mask, trusthost **superset, trusthost **subset) {
243 *superset = th_getsmallestsupersetbyhost(ip, mask);
244 *subset = th_getsubsetbyhost(ip, mask);
245 }
246
247 void trusts_flush(void (*thflush)(trusthost *), void (*tgflush)(trustgroup *)) {
248 trustgroup *tg;
249 trusthost *th;
250 time_t t = time(NULL);
251
252 for(tg=tglist;tg;tg=tg->next) {
253 if(tg->count > 0)
254 tg->lastseen = t;
255
256 tgflush(tg);
257
258 for(th=tg->hosts;th;th=th->next) {
259 if(th->count > 0)
260 th->lastseen = t;
261
262 thflush(th);
263 }
264 }
265 }
266
267 trustgroup *tg_strtotg(char *name) {
268 unsigned long id;
269 trustgroup *tg;
270
271 /* legacy format */
272 if(name[0] == '#') {
273 id = strtoul(&name[1], NULL, 10);
274 if(!id)
275 return NULL;
276
277 for(tg=tglist;tg;tg=tg->next)
278 if(tg->id == id)
279 return tg;
280 }
281
282 for(tg=tglist;tg;tg=tg->next)
283 if(!match(name, tg->name->content))
284 return tg;
285
286 id = strtoul(name, NULL, 10);
287 if(!id)
288 return NULL;
289
290 /* legacy format */
291 for(tg=tglist;tg;tg=tg->next)
292 if(tg->id == id)
293 return tg;
294
295 return NULL;
296 }
297
298 void th_adjusthosts(trusthost *th, trusthost *superset, trusthost *subset) {
299 /*
300 * First and foremost, CIDR doesn't allow hosts to cross boundaries, i.e. everything with a smaller prefix
301 * is entirely contained with the prefix that is one smaller.
302 * e.g. 0.0.0.0/23, 0.0.0.128/23, you can't have a single prefix for 0.0.0.64-0.0.0.192, instead
303 * you have two, 0.0.0.64/26 and 0.0.0.128/26.
304 *
305 * This makes the code MUCH easier as the entire thing is one huge set/tree.
306 *
307 * Four cases here:
308 * 1: host isn't covered by any existing hosts.
309 * 2: host is covered by a less specific one only, e.g. adding 0.0.0.1/32, while 0.0.0.0/24 already exists.
310 * 3: host is covered by a more specific one only, e.g. adding 0.0.0.0/24 while 0.0.0.1/32 already exists
311 * (note there might be more than one more specific host, e.g. 0.0.0.1/32 and 0.0.0.2/32).
312 * 4: covered by more and less specific cases, e.g. adding 0.0.0.0/24 to: { 0.0.0.1/32, 0.0.0.2/32, 0.0.0.0/16 }.
313 *
314 * CASE 1
315 * ------
316 *
317 * !superset && !subset
318 *
319 * Scan through the host hash and add any clients which match our host, this is exactly the same as case 3
320 * but without needing to check (though checking doesn't hurt), so we'll just use the code for that.
321 *
322 * CASE 2
323 * ------
324 *
325 * superset && !subset
326 *
327 * We have the less specific host in 'superset', we know it is the only one so pull out clients in it's
328 * ->users list matching our new host.
329 * No need to look for extra hosts in the main nick hash as they're all covered already.
330 *
331 * CASE 3
332 * ------
333 *
334 * !superset && subset
335 *
336 * We have one host in 'subset', but there might be more than one, we don't care though!
337 * We can scan the entire host hash and pull out any hosts that match us and don't have
338 * a trust group already, this ignores any with a more specific prefix.
339 *
340 * CASE 4
341 * ------
342 *
343 * superset && subset
344 *
345 * Here we first fix up the ones less specific then us, so we just perform what we did for case 2,
346 * then we perform what we did for case 3.
347 *
348 * So in summary:
349 * CASE 1: DO 3
350 * CASE 2: (work)
351 * CASE 3: (work)
352 * CASE 4: DO 2; DO 3
353 * Or:
354 * if(2 || 4) : DO 2
355 * if(1 || 3 || 4): DO 3
356 */
357
358 /* we let the compiler do the boolean minimisation for clarity reasons */
359
360 if((superset && !subset) || (superset && subset)) { /* cases 2 and 4 */
361 nick *np, *nnp;
362 for(np=superset->users;np;np=nnp) {
363 nnp = nextbytrust(np);
364 if((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip) {
365 trusts_lostnick(np, 1);
366 trusts_newnick(np, 1);
367 }
368 }
369 }
370
371 if((!superset && !subset) || (!superset && subset) || (superset && subset)) { /* cases 1, 3 and 4 */
372 nick *np;
373 int i;
374
375 for(i=0;i<NICKHASHSIZE;i++)
376 for(np=nicktable[i];np;np=np->next)
377 if(!gettrusthost(np) && ((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip))
378 trusts_newnick(np, 1);
379 }
380 }
381
382 unsigned int nexttgmarker(void) {
383 static unsigned int tgmarker = 0;
384 trustgroup *tg;
385
386 tgmarker++;
387 if(!tgmarker) {
388 /* If we wrapped to zero, zap the marker on all groups */
389 for(tg=tglist;tg;tg=tg->next)
390 tg->marker=0;
391
392 tgmarker++;
393 }
394
395 return tgmarker;
396 }
397
398 unsigned int nextthmarker(void) {
399 static unsigned int thmarker = 0;
400 trustgroup *tg;
401 trusthost *th;
402
403 thmarker++;
404 if(!thmarker) {
405 /* If we wrapped to zero, zap the marker on all hosts */
406 for(tg=tglist;tg;tg=tg->next)
407 for(th=tg->hosts;th;th=th->next)
408 th->marker=0;
409
410 thmarker++;
411 }
412
413 return thmarker;
414 }
415
416 trustgroup *tg_inttotg(unsigned int id) {
417 trustgroup *tg;
418
419 for(tg=tglist;tg;tg=tg->next)
420 if(tg->id == id)
421 return tg;
422
423 return NULL;
424 }
425