ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/hostmask.c
Revision: 1371
Committed: Wed Apr 25 19:32:21 2012 UTC (13 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/hostmask.c
File size: 26638 byte(s)
Log Message:
- "UNKLINE bla@bla.net" may accidentaly remove existing klines such as *@bla.* - Fixed

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * hostmask.c: Code to efficiently find IP & hostmask based configs.
4 *
5 * Copyright (C) 2005 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "memory.h"
27 #include "ircd_defs.h"
28 #include "list.h"
29 #include "conf.h"
30 #include "hostmask.h"
31 #include "numeric.h"
32 #include "send.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35
36 #ifdef IPV6
37 static int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *);
38 static uint32_t hash_ipv6(struct irc_ssaddr *, int);
39 #endif
40 static int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
41 static uint32_t hash_ipv4(struct irc_ssaddr *, int);
42
43 #define DigitParse(ch) do { \
44 if (ch >= '0' && ch <= '9') \
45 ch = ch - '0'; \
46 else if (ch >= 'A' && ch <= 'F') \
47 ch = ch - 'A' + 10; \
48 else if (ch >= 'a' && ch <= 'f') \
49 ch = ch - 'a' + 10; \
50 } while (0);
51
52 /* The mask parser/type determination code... */
53
54 /* int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *);
55 * Input: A possible IPV6 address as a string.
56 * Output: An integer describing whether it is an IPV6 or hostmask,
57 * an address(if it is IPV6), a bitlength(if it is IPV6).
58 * Side effects: None
59 * Comments: Called from parse_netmask
60 */
61 /* Fixed so ::/0 (any IPv6 address) is valid
62 Also a bug in DigitParse above.
63 -Gozem 2002-07-19 gozem@linux.nu
64 */
65 #ifdef IPV6
66 static int
67 try_parse_v6_netmask(const char *text, struct irc_ssaddr *addr, int *b)
68 {
69 const char *p;
70 char c;
71 int d[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
72 int dp = 0;
73 int nyble = 4;
74 int finsert = -1;
75 int bits = 128;
76 int deficit = 0;
77 short dc[8];
78 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
79
80 for (p = text; (c = *p); p++)
81 if (IsXDigit(c))
82 {
83 if (nyble == 0)
84 return HM_HOST;
85 DigitParse(c);
86 d[dp] |= c << (4 * --nyble);
87 }
88 else if (c == ':')
89 {
90 if (p > text && *(p - 1) == ':')
91 {
92 if (finsert >= 0)
93 return HM_HOST;
94 finsert = dp;
95 }
96 else
97 {
98 /* If there were less than 4 hex digits, e.g. :ABC: shift right
99 * so we don't interpret it as ABC0 -A1kmm */
100 d[dp] = d[dp] >> 4 * nyble;
101 nyble = 4;
102 if (++dp >= 8)
103 return HM_HOST;
104 }
105 }
106 else if (c == '*')
107 {
108 /* * must be last, and * is ambiguous if there is a ::... -A1kmm */
109 if (finsert >= 0 || *(p + 1) || dp == 0 || *(p - 1) != ':')
110 return HM_HOST;
111 bits = dp * 16;
112 }
113 else if (c == '/')
114 {
115 char *after;
116
117 d[dp] = d[dp] >> 4 * nyble;
118 dp++;
119 bits = strtoul(p + 1, &after, 10);
120
121 if (bits < 0 || *after)
122 return HM_HOST;
123 if (bits > dp * 4 && !(finsert >= 0 && bits <= 128))
124 return HM_HOST;
125 break;
126 }
127 else
128 return HM_HOST;
129
130 d[dp] = d[dp] >> 4 * nyble;
131
132 if (c == 0)
133 dp++;
134 if (finsert < 0 && bits == 0)
135 bits = dp * 16;
136
137 /* How many words are missing? -A1kmm */
138 deficit = bits / 16 + ((bits % 16) ? 1 : 0) - dp;
139
140 /* Now fill in the gaps(from ::) in the copied table... -A1kmm */
141 for (dp = 0, nyble = 0; dp < 8; dp++)
142 {
143 if (nyble == finsert && deficit)
144 {
145 dc[dp] = 0;
146 deficit--;
147 }
148 else
149 dc[dp] = d[nyble++];
150 }
151
152 /* Set unused bits to 0... -A1kmm */
153 if (bits < 128 && (bits % 16 != 0))
154 dc[bits / 16] &= ~((1 << (15 - bits % 16)) - 1);
155 for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; dp++)
156 dc[dp] = 0;
157
158 /* And assign... -A1kmm */
159 if (addr)
160 for (dp = 0; dp < 8; dp++)
161 /* The cast is a kludge to make netbsd work. */
162 ((unsigned short *)&v6->sin6_addr)[dp] = htons(dc[dp]);
163
164 if (b != NULL)
165 *b = bits;
166 return HM_IPV6;
167 }
168 #endif
169
170 /* int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
171 * Input: A possible IPV4 address as a string.
172 * Output: An integer describing whether it is an IPV4 or hostmask,
173 * an address(if it is IPV4), a bitlength(if it is IPV4).
174 * Side effects: None
175 * Comments: Called from parse_netmask
176 */
177 static int
178 try_parse_v4_netmask(const char *text, struct irc_ssaddr *addr, int *b)
179 {
180 const char *p;
181 const char *digits[4];
182 unsigned char addb[4];
183 int n = 0, bits = 0;
184 char c;
185 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
186
187 digits[n++] = text;
188
189 for (p = text; (c = *p); p++)
190 if (c >= '0' && c <= '9') /* empty */
191 ;
192 else if (c == '.')
193 {
194 if (n >= 4)
195 return HM_HOST;
196
197 digits[n++] = p + 1;
198 }
199 else if (c == '*')
200 {
201 if (*(p + 1) || n == 0 || *(p - 1) != '.')
202 return HM_HOST;
203
204 bits = (n - 1) * 8;
205 break;
206 }
207 else if (c == '/')
208 {
209 char *after;
210 bits = strtoul(p + 1, &after, 10);
211
212 if (!bits || *after)
213 return HM_HOST;
214 if (bits > n * 8)
215 return HM_HOST;
216
217 break;
218 }
219 else
220 return HM_HOST;
221
222 if (n < 4 && bits == 0)
223 bits = n * 8;
224 if (bits)
225 while (n < 4)
226 digits[n++] = "0";
227
228 for (n = 0; n < 4; n++)
229 addb[n] = strtoul(digits[n], NULL, 10);
230
231 if (bits == 0)
232 bits = 32;
233
234 /* Set unused bits to 0... -A1kmm */
235 if (bits < 32 && bits % 8)
236 addb[bits / 8] &= ~((1 << (8 - bits % 8)) - 1);
237 for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; n++)
238 addb[n] = 0;
239 if (addr)
240 v4->sin_addr.s_addr =
241 htonl(addb[0] << 24 | addb[1] << 16 | addb[2] << 8 | addb[3]);
242 if (b != NULL)
243 *b = bits;
244 return HM_IPV4;
245 }
246
247 /* int parse_netmask(const char *, struct irc_ssaddr *, int *);
248 * Input: A hostmask, or an IPV4/6 address.
249 * Output: An integer describing whether it is an IPV4, IPV6 address or a
250 * hostmask, an address(if it is an IP mask),
251 * a bitlength(if it is IP mask).
252 * Side effects: None
253 */
254 int
255 parse_netmask(const char *text, struct irc_ssaddr *addr, int *b)
256 {
257 #ifdef IPV6
258 if (strchr(text, ':'))
259 return try_parse_v6_netmask(text, addr, b);
260 #endif
261 if (strchr(text, '.'))
262 return try_parse_v4_netmask(text, addr, b);
263 return HM_HOST;
264 }
265
266 /* The address matching stuff... */
267 /* int match_ipv6(struct irc_ssaddr *, struct irc_ssaddr *, int)
268 * Input: An IP address, an IP mask, the number of bits in the mask.
269 * Output: if match, -1 else 0
270 * Side effects: None
271 */
272 #ifdef IPV6
273 int
274 match_ipv6(struct irc_ssaddr *addr, struct irc_ssaddr *mask, int bits)
275 {
276 int i, m, n = bits / 8;
277 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
278 struct sockaddr_in6 *v6mask = (struct sockaddr_in6 *)mask;
279
280 for (i = 0; i < n; i++)
281 if (v6->sin6_addr.s6_addr[i] != v6mask->sin6_addr.s6_addr[i])
282 return 0;
283 if ((m = bits % 8) == 0)
284 return -1;
285 if ((v6->sin6_addr.s6_addr[n] & ~((1 << (8 - m)) - 1)) ==
286 v6mask->sin6_addr.s6_addr[n])
287 return -1;
288 return 0;
289 }
290 #endif
291 /* int match_ipv4(struct irc_ssaddr *, struct irc_ssaddr *, int)
292 * Input: An IP address, an IP mask, the number of bits in the mask.
293 * Output: if match, -1 else 0
294 * Side Effects: None
295 */
296 int
297 match_ipv4(struct irc_ssaddr *addr, struct irc_ssaddr *mask, int bits)
298 {
299 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
300 struct sockaddr_in *v4mask = (struct sockaddr_in *)mask;
301
302 if ((ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1)) !=
303 ntohl(v4mask->sin_addr.s_addr))
304 return 0;
305 return -1;
306 }
307
308 /*
309 * mask_addr
310 *
311 * inputs - pointer to the ip to mask
312 * - bitlen
313 * output - NONE
314 * side effects -
315 */
316 void
317 mask_addr(struct irc_ssaddr *ip, int bits)
318 {
319 int mask;
320 #ifdef IPV6
321 struct sockaddr_in6 *v6_base_ip;
322 int i, m, n;
323 #endif
324 struct sockaddr_in *v4_base_ip;
325
326 #ifdef IPV6
327 if (ip->ss.ss_family != AF_INET6)
328 #endif
329 {
330 v4_base_ip = (struct sockaddr_in *)ip;
331
332 mask = ~((1 << (32 - bits)) - 1);
333 v4_base_ip->sin_addr.s_addr = htonl(ntohl(v4_base_ip->sin_addr.s_addr) & mask);
334 }
335 #ifdef IPV6
336 else
337 {
338 n = bits / 8;
339 m = bits % 8;
340 v6_base_ip = (struct sockaddr_in6 *)ip;
341
342 mask = ~((1 << (8 - m)) -1 );
343 v6_base_ip->sin6_addr.s6_addr[n] = v6_base_ip->sin6_addr.s6_addr[n] & mask;
344
345 for (i = n + 1; i < 16; i++)
346 v6_base_ip->sin6_addr.s6_addr[i] = 0;
347 }
348 #endif
349 }
350
351 /* Hashtable stuff...now external as its used in m_stats.c */
352 dlink_list atable[ATABLE_SIZE];
353
354 void
355 init_host_hash(void)
356 {
357 memset(&atable, 0, sizeof(atable));
358 }
359
360 /* unsigned long hash_ipv4(struct irc_ssaddr*)
361 * Input: An IP address.
362 * Output: A hash value of the IP address.
363 * Side effects: None
364 */
365 static uint32_t
366 hash_ipv4(struct irc_ssaddr *addr, int bits)
367 {
368 if (bits != 0)
369 {
370 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
371 uint32_t av = ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1);
372
373 return (av ^ (av >> 12) ^ (av >> 24)) & (ATABLE_SIZE - 1);
374 }
375
376 return 0;
377 }
378
379 /* unsigned long hash_ipv6(struct irc_ssaddr*)
380 * Input: An IP address.
381 * Output: A hash value of the IP address.
382 * Side effects: None
383 */
384 #ifdef IPV6
385 static uint32_t
386 hash_ipv6(struct irc_ssaddr *addr, int bits)
387 {
388 uint32_t v = 0, n;
389 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
390
391 for (n = 0; n < 16; n++)
392 {
393 if (bits >= 8)
394 {
395 v ^= v6->sin6_addr.s6_addr[n];
396 bits -= 8;
397 }
398 else if (bits)
399 {
400 v ^= v6->sin6_addr.s6_addr[n] & ~((1 << (8 - bits)) - 1);
401 return v & (ATABLE_SIZE - 1);
402 }
403 else
404 return v & (ATABLE_SIZE - 1);
405 }
406 return v & (ATABLE_SIZE - 1);
407 }
408 #endif
409
410 /* int hash_text(const char *start)
411 * Input: The start of the text to hash.
412 * Output: The hash of the string between 1 and (TH_MAX-1)
413 * Side-effects: None.
414 */
415 static uint32_t
416 hash_text(const char *start)
417 {
418 const char *p = start;
419 uint32_t h = 0;
420
421 for (; *p; ++p)
422 h = (h << 4) - (h + (unsigned char)ToLower(*p));
423
424 return h & (ATABLE_SIZE - 1);
425 }
426
427 /* unsigned long get_hash_mask(const char *)
428 * Input: The text to hash.
429 * Output: The hash of the string right of the first '.' past the last
430 * wildcard in the string.
431 * Side-effects: None.
432 */
433 static uint32_t
434 get_mask_hash(const char *text)
435 {
436 const char *hp = "", *p;
437
438 for (p = text + strlen(text) - 1; p >= text; p--)
439 if (IsMWildChar(*p))
440 return hash_text(hp);
441 else if (*p == '.')
442 hp = p + 1;
443 return hash_text(text);
444 }
445
446 /* struct AccessItem *find_conf_by_address(const char *, struct irc_ssaddr *,
447 * int type, int fam, const char *username)
448 * Input: The hostname, the address, the type of mask to find, the address
449 * family, the username.
450 * Output: The matching value with the highest precedence.
451 * Side-effects: None
452 * Note: Setting bit 0 of the type means that the username is ignored.
453 * Warning: IsNeedPassword for everything that is not an auth{} entry
454 * should always be true (i.e. aconf->flags & CONF_FLAGS_NEED_PASSWORD == 0)
455 */
456 struct AccessItem *
457 find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int type,
458 int fam, const char *username, const char *password, int do_match)
459 {
460 unsigned int hprecv = 0;
461 dlink_node *ptr = NULL;
462 struct AccessItem *hprec = NULL;
463 struct AddressRec *arec;
464 int b;
465 int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
466
467 if (username == NULL)
468 username = "";
469 if (password == NULL)
470 password = "";
471
472 if (addr)
473 {
474 /* Check for IPV6 matches... */
475 #ifdef IPV6
476 if (fam == AF_INET6)
477 {
478 for (b = 128; b >= 0; b -= 16)
479 {
480 DLINK_FOREACH(ptr, atable[hash_ipv6(addr, b)].head)
481 {
482 arec = ptr->data;
483
484 if (arec->type == (type & ~0x1) &&
485 arec->precedence > hprecv &&
486 arec->masktype == HM_IPV6 &&
487 match_ipv6(addr, &arec->Mask.ipa.addr,
488 arec->Mask.ipa.bits) &&
489 (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
490 (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
491 match_conf_password(password, arec->aconf)))
492 {
493 hprecv = arec->precedence;
494 hprec = arec->aconf;
495 }
496 }
497 }
498 }
499 else
500 #endif
501 if (fam == AF_INET)
502 {
503 for (b = 32; b >= 0; b -= 8)
504 {
505 DLINK_FOREACH(ptr, atable[hash_ipv4(addr, b)].head)
506 {
507 arec = ptr->data;
508
509 if (arec->type == (type & ~0x1) &&
510 arec->precedence > hprecv &&
511 arec->masktype == HM_IPV4 &&
512 match_ipv4(addr, &arec->Mask.ipa.addr,
513 arec->Mask.ipa.bits) &&
514 (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
515 (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
516 match_conf_password(password, arec->aconf)))
517 {
518 hprecv = arec->precedence;
519 hprec = arec->aconf;
520 }
521 }
522 }
523 }
524 }
525
526 if (name != NULL)
527 {
528 const char *p = name;
529
530 while (1)
531 {
532 DLINK_FOREACH(ptr, atable[hash_text(p)].head)
533 {
534 arec = ptr->data;
535 if ((arec->type == (type & ~0x1)) &&
536 arec->precedence > hprecv &&
537 (arec->masktype == HM_HOST) &&
538 cmpfunc(arec->Mask.hostname, name) == do_match &&
539 (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
540 (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
541 match_conf_password(password, arec->aconf)))
542 {
543 hprecv = arec->precedence;
544 hprec = arec->aconf;
545 }
546 }
547 p = strchr(p, '.');
548 if (p == NULL)
549 break;
550 p++;
551 }
552
553 DLINK_FOREACH(ptr, atable[0].head)
554 {
555 arec = ptr->data;
556
557 if (arec->type == (type & ~0x1) &&
558 arec->precedence > hprecv &&
559 arec->masktype == HM_HOST &&
560 cmpfunc(arec->Mask.hostname, name) == do_match &&
561 (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
562 (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
563 match_conf_password(password, arec->aconf)))
564 {
565 hprecv = arec->precedence;
566 hprec = arec->aconf;
567 }
568 }
569 }
570
571 return hprec;
572 }
573
574 /* struct AccessItem* find_address_conf(const char*, const char*,
575 * struct irc_ssaddr*, int, char *);
576 * Input: The hostname, username, address, address family.
577 * Output: The applicable AccessItem.
578 * Side-effects: None
579 */
580 struct AccessItem *
581 find_address_conf(const char *host, const char *user,
582 struct irc_ssaddr *ip, int aftype, char *password)
583 {
584 struct AccessItem *iconf, *kconf;
585
586 /* Find the best I-line... If none, return NULL -A1kmm */
587 if ((iconf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user,
588 password, 1)) == NULL)
589 return NULL;
590
591 /* If they are exempt from K-lines, return the best I-line. -A1kmm */
592 if (IsConfExemptKline(iconf))
593 return iconf;
594
595 /* Find the best K-line... -A1kmm */
596 kconf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
597
598 /* If they are K-lined, return the K-line. Otherwise, return the
599 * I-line. -A1kmm */
600 if (kconf != NULL)
601 return kconf;
602
603 kconf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1);
604 if (kconf != NULL && !IsConfExemptGline(iconf))
605 return kconf;
606
607 return iconf;
608 }
609
610 struct AccessItem *
611 find_gline_conf(const char *host, const char *user,
612 struct irc_ssaddr *ip, int aftype)
613 {
614 struct AccessItem *eline;
615
616 eline = find_conf_by_address(host, ip, CONF_EXEMPTKLINE, aftype,
617 user, NULL, 1);
618 if (eline != NULL)
619 return eline;
620
621 return find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1);
622 }
623
624 /* find_kline_conf
625 *
626 * inputs - pointer to hostname
627 * - pointer to username
628 * - incoming IP and type (IPv4 vs. IPv6)
629 * outut - pointer to kline conf if found NULL if not
630 * side effects -
631 */
632 struct AccessItem *
633 find_kline_conf(const char *host, const char *user,
634 struct irc_ssaddr *ip, int aftype)
635 {
636 struct AccessItem *eline;
637
638 eline = find_conf_by_address(host, ip, CONF_EXEMPTKLINE, aftype,
639 user, NULL, 1);
640 if (eline != NULL)
641 return eline;
642
643 return find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
644 }
645
646 /* struct AccessItem* find_dline_conf(struct irc_ssaddr*, int)
647 *
648 * Input: An address, an address family.
649 * Output: The best matching D-line or exempt line.
650 * Side effects: None.
651 */
652 struct AccessItem *
653 find_dline_conf(struct irc_ssaddr *addr, int aftype)
654 {
655 struct AccessItem *eline;
656
657 eline = find_conf_by_address(NULL, addr, CONF_EXEMPTDLINE | 1, aftype,
658 NULL, NULL, 1);
659 if (eline != NULL)
660 return eline;
661
662 return find_conf_by_address(NULL, addr, CONF_DLINE | 1, aftype, NULL, NULL, 1);
663 }
664
665 /* void add_conf_by_address(int, struct AccessItem *aconf)
666 * Input:
667 * Output: None
668 * Side-effects: Adds this entry to the hash table.
669 */
670 void
671 add_conf_by_address(const unsigned int type, struct AccessItem *aconf)
672 {
673 const char *address;
674 const char *username;
675 static unsigned int prec_value = 0xFFFFFFFF;
676 int bits = 0;
677 struct AddressRec *arec;
678
679 address = aconf->host;
680 username = aconf->user;
681
682 assert(type != 0);
683 assert(aconf != NULL);
684
685 if (EmptyString(address))
686 address = "/NOMATCH!/";
687
688 arec = MyMalloc(sizeof(struct AddressRec));
689 arec->masktype = parse_netmask(address, &arec->Mask.ipa.addr, &bits);
690 arec->Mask.ipa.bits = bits;
691 arec->username = username;
692 arec->aconf = aconf;
693 arec->precedence = prec_value--;
694 arec->type = type;
695
696 switch (arec->masktype)
697 {
698 case HM_IPV4:
699 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
700 bits -= bits % 8;
701 dlinkAdd(arec, &arec->node, &atable[hash_ipv4(&arec->Mask.ipa.addr, bits)]);
702 break;
703 #ifdef IPV6
704 case HM_IPV6:
705 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
706 bits -= bits % 16;
707 dlinkAdd(arec, &arec->node, &atable[hash_ipv6(&arec->Mask.ipa.addr, bits)]);
708 break;
709 #endif
710 default: /* HM_HOST */
711 arec->Mask.hostname = address;
712 dlinkAdd(arec, &arec->node, &atable[get_mask_hash(address)]);
713 break;
714 }
715 }
716
717 /* void delete_one_address(const char*, struct AccessItem*)
718 * Input: An address string, the associated AccessItem.
719 * Output: None
720 * Side effects: Deletes an address record. Frees the AccessItem if there
721 * is nothing referencing it, sets it as illegal otherwise.
722 */
723 void
724 delete_one_address_conf(const char *address, struct AccessItem *aconf)
725 {
726 int bits = 0;
727 uint32_t hv = 0;
728 dlink_node *ptr = NULL, *ptr_next = NULL;
729 struct irc_ssaddr addr;
730
731 switch (parse_netmask(address, &addr, &bits))
732 {
733 case HM_IPV4:
734 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
735 bits -= bits % 8;
736 hv = hash_ipv4(&addr, bits);
737 break;
738 #ifdef IPV6
739 case HM_IPV6:
740 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
741 bits -= bits % 16;
742 hv = hash_ipv6(&addr, bits);
743 break;
744 #endif
745 default: /* HM_HOST */
746 hv = get_mask_hash(address);
747 break;
748 }
749
750 DLINK_FOREACH_SAFE(ptr, ptr_next, atable[hv].head)
751 {
752 struct AddressRec *arec = ptr->data;
753
754 if (arec->aconf == aconf)
755 {
756 dlinkDelete(&arec->node, &atable[hv]);
757 aconf->status |= CONF_ILLEGAL;
758
759 if (!aconf->clients)
760 free_access_item(aconf);
761
762 MyFree(arec);
763 return;
764 }
765 }
766 }
767
768 /* void clear_out_address_conf(void)
769 * Input: None
770 * Output: None
771 * Side effects: Clears out all address records in the hash table,
772 * frees them, and frees the AccessItems if nothing references
773 * them, otherwise sets them as illegal.
774 */
775 void
776 clear_out_address_conf(void)
777 {
778 unsigned int i = 0;
779 dlink_node *ptr = NULL, *ptr_next = NULL;
780
781 for (i = 0; i < ATABLE_SIZE; ++i)
782 {
783 ptr = ptr_next = NULL;
784
785 DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head)
786 {
787 struct AddressRec *arec = ptr->data;
788
789 /* We keep the temporary K-lines and destroy the
790 * permanent ones, just to be confusing :) -A1kmm
791 */
792 if (!(arec->aconf->flags & CONF_FLAGS_TEMPORARY))
793 {
794 dlinkDelete(&arec->node, &atable[i]);
795 /* unlink it from link list - Dianora */
796 arec->aconf->status |= CONF_ILLEGAL;
797
798 if (!arec->aconf->clients)
799 free_access_item(arec->aconf);
800 MyFree(arec);
801 }
802 }
803 }
804 }
805
806 static void
807 hostmask_send_expiration(struct AddressRec *arec)
808 {
809 char ban_type = '\0';
810
811 if (!ConfigFileEntry.tkline_expire_notices)
812 return;
813
814 switch (arec->type)
815 {
816 case CONF_KLINE:
817 ban_type = 'K';
818 break;
819 case CONF_DLINE:
820 ban_type = 'D';
821 break;
822 case CONF_GLINE:
823 ban_type = 'G';
824 break;
825 }
826
827 sendto_realops_flags(UMODE_ALL, L_ALL,
828 "Temporary %c-line for [%s@%s] expired", ban_type,
829 (arec->aconf->user) ? arec->aconf->user : "*",
830 (arec->aconf->host) ? arec->aconf->host : "*");
831 }
832
833 void
834 hostmask_expire_temporary(void)
835 {
836 unsigned int i = 0;
837 dlink_node *ptr = NULL, *ptr_next = NULL;
838
839 for (i = 0; i < ATABLE_SIZE; ++i)
840 {
841 ptr = ptr_next = NULL;
842
843 DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head)
844 {
845 struct AddressRec *arec = ptr->data;
846
847 if (!IsConfTemporary(arec->aconf) || arec->aconf->hold > CurrentTime)
848 continue;
849
850 switch (arec->type)
851 {
852 case CONF_KLINE:
853 case CONF_DLINE:
854 case CONF_GLINE:
855 hostmask_send_expiration(arec);
856
857 dlinkDelete(&arec->node, &atable[i]);
858 free_access_item(arec->aconf);
859 MyFree(arec);
860 break;
861 }
862 }
863 }
864 }
865
866 /*
867 * show_iline_prefix()
868 *
869 * inputs - pointer to struct Client requesting output
870 * - pointer to struct AccessItem
871 * - name to which iline prefix will be prefixed to
872 * output - pointer to static string with prefixes listed in ascii form
873 * side effects - NONE
874 */
875 char *
876 show_iline_prefix(struct Client *sptr, struct AccessItem *aconf, const char *name)
877 {
878 static char prefix_of_host[USERLEN + 14];
879 char *prefix_ptr = prefix_of_host;
880
881 if (IsNoTilde(aconf))
882 *prefix_ptr++ = '-';
883 if (IsLimitIp(aconf))
884 *prefix_ptr++ = '!';
885 if (IsNeedIdentd(aconf))
886 *prefix_ptr++ = '+';
887 if (!IsNeedPassword(aconf))
888 *prefix_ptr++ = '&';
889 if (IsConfExemptResv(aconf))
890 *prefix_ptr++ = '$';
891 if (IsNoMatchIp(aconf))
892 *prefix_ptr++ = '%';
893 if (IsConfDoSpoofIp(aconf))
894 *prefix_ptr++ = '=';
895 if (MyOper(sptr) && IsConfExemptKline(aconf))
896 *prefix_ptr++ = '^';
897 if (MyOper(sptr) && IsConfExemptGline(aconf))
898 *prefix_ptr++ = '_';
899 if (MyOper(sptr) && IsConfExemptLimits(aconf))
900 *prefix_ptr++ = '>';
901 if (IsConfCanFlood(aconf))
902 *prefix_ptr++ = '|';
903
904 strlcpy(prefix_ptr, name, USERLEN+1);
905
906 return prefix_of_host;
907 }
908
909 /* report_auth()
910 *
911 * Inputs: pointer to client to report to
912 * Output: None
913 * Side effects: Reports configured auth{} blocks to client_p
914 */
915 void
916 report_auth(struct Client *client_p)
917 {
918 struct ConfItem *conf;
919 struct AccessItem *aconf;
920 dlink_node *ptr = NULL;
921 unsigned int i;
922
923
924 for (i = 0; i < ATABLE_SIZE; ++i)
925 {
926 ptr = NULL;
927
928 DLINK_FOREACH(ptr, atable[i].head)
929 {
930 struct AddressRec *arec = ptr->data;
931
932 if (arec->type == CONF_CLIENT)
933 {
934 aconf = arec->aconf;
935
936 if (!MyOper(client_p) && IsConfDoSpoofIp(aconf))
937 continue;
938
939 conf = unmap_conf_item(aconf);
940
941 /* We are doing a partial list, based on what matches the u@h of the
942 * sender, so prepare the strings for comparing --fl_
943 */
944 if (ConfigFileEntry.hide_spoof_ips)
945 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
946 client_p->name, 'I',
947 conf->name == NULL ? "*" : conf->name,
948 show_iline_prefix(client_p, aconf, aconf->user),
949 IsConfDoSpoofIp(aconf) ? "255.255.255.255" :
950 aconf->host, aconf->port,
951 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
952
953 else
954 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
955 client_p->name, 'I',
956 conf->name == NULL ? "*" : conf->name,
957 show_iline_prefix(client_p, aconf, aconf->user),
958 aconf->host, aconf->port,
959 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
960 }
961 }
962 }
963 }
964
965 /* report_Klines()
966 * Inputs: Client to report to,
967 * type(==0 for perm, !=0 for temporary)
968 * mask
969 * Output: None
970 * Side effects: Reports configured K(or k)-lines to client_p.
971 */
972 void
973 report_Klines(struct Client *client_p, int tkline)
974 {
975 struct AccessItem *aconf = NULL;
976 unsigned int i = 0;
977 const char *p = NULL;
978 dlink_node *ptr = NULL;
979
980 if (tkline)
981 p = "k";
982 else
983 p = "K";
984
985 for (i = 0; i < ATABLE_SIZE; ++i)
986 {
987 ptr = NULL;
988
989 DLINK_FOREACH(ptr, atable[i].head)
990 {
991 struct AddressRec *arec = ptr->data;
992
993 if (arec->type == CONF_KLINE)
994 {
995 if ((tkline && !((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)) ||
996 (!tkline && ((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)))
997 continue;
998
999 if (HasUMode(client_p, UMODE_OPER))
1000 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1001 client_p->name, p, aconf->host, aconf->user,
1002 aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
1003 else
1004 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1005 client_p->name, p, aconf->host, aconf->user,
1006 aconf->reason, "");
1007 }
1008 }
1009 }
1010 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision