ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/hostmask.c
Revision: 5845
Committed: Sun Apr 26 17:48:00 2015 UTC (8 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 20616 byte(s)
Log Message:
- hostmask.c:clear_out_address_conf(): removed useless test on arec->conf->until. Temporary
  server bans are always stored in the databases, so it's enough to test for IsConfDatabase()

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 2001-2015 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file hostmask.c
23 * \brief Code to efficiently find IP & hostmask based configs.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "memory.h"
29 #include "ircd_defs.h"
30 #include "list.h"
31 #include "conf.h"
32 #include "hostmask.h"
33 #include "send.h"
34 #include "irc_string.h"
35 #include "ircd.h"
36
37
38 #define DigitParse(ch) do { \
39 if (ch >= '0' && ch <= '9') \
40 ch = ch - '0'; \
41 else if (ch >= 'A' && ch <= 'F') \
42 ch = ch - 'A' + 10; \
43 else if (ch >= 'a' && ch <= 'f') \
44 ch = ch - 'a' + 10; \
45 } while (0);
46
47 /* Hashtable stuff...now external as it's used in m_stats.c */
48 dlink_list atable[ATABLE_SIZE];
49
50 /* The mask parser/type determination code... */
51
52 /* int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *);
53 * Input: A possible IPV6 address as a string.
54 * Output: An integer describing whether it is an IPV6 or hostmask,
55 * an address(if it is IPV6), a bitlength(if it is IPV6).
56 * Side effects: None
57 * Comments: Called from parse_netmask
58 */
59 /* Fixed so ::/0 (any IPv6 address) is valid
60 Also a bug in DigitParse above.
61 -Gozem 2002-07-19 gozem@linux.nu
62 */
63 static int
64 try_parse_v6_netmask(const char *text, struct irc_ssaddr *addr, int *b)
65 {
66 char c;
67 int d[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
68 int dp = 0;
69 int nyble = 4;
70 int finsert = -1;
71 int bits = 128;
72 int deficit = 0;
73 short dc[8];
74 struct sockaddr_in6 *const v6 = (struct sockaddr_in6 *)addr;
75
76 for (const char *p = text; (c = *p); ++p)
77 {
78 if (IsXDigit(c))
79 {
80 if (nyble == 0)
81 return HM_HOST;
82 DigitParse(c);
83 d[dp] |= c << (4 * --nyble);
84 }
85 else if (c == ':')
86 {
87 if (p > text && *(p - 1) == ':')
88 {
89 if (finsert >= 0)
90 return HM_HOST;
91 finsert = dp;
92 }
93 else
94 {
95 /* If there were less than 4 hex digits, e.g. :ABC: shift right
96 * so we don't interpret it as ABC0 -A1kmm */
97 d[dp] = d[dp] >> 4 * nyble;
98 nyble = 4;
99 if (++dp >= 8)
100 return HM_HOST;
101 }
102 }
103 else if (c == '*')
104 {
105 /* * must be last, and * is ambiguous if there is a ::... -A1kmm */
106 if (finsert >= 0 || *(p + 1) || dp == 0 || *(p - 1) != ':')
107 return HM_HOST;
108 bits = dp * 16;
109 }
110 else if (c == '/')
111 {
112 char *after;
113
114 d[dp] = d[dp] >> 4 * nyble;
115 ++dp;
116 bits = strtoul(p + 1, &after, 10);
117
118 if (bits < 0 || *after)
119 return HM_HOST;
120 if (bits > dp * 4 && !(finsert >= 0 && bits <= 128))
121 return HM_HOST;
122 break;
123 }
124 else
125 return HM_HOST;
126 }
127
128 d[dp] = d[dp] >> 4 * nyble;
129
130 if (c == 0)
131 ++dp;
132 if (finsert < 0 && bits == 0)
133 bits = dp * 16;
134
135 /* How many words are missing? -A1kmm */
136 deficit = bits / 16 + ((bits % 16) ? 1 : 0) - dp;
137
138 /* Now fill in the gaps(from ::) in the copied table... -A1kmm */
139 for (dp = 0, nyble = 0; dp < 8; ++dp)
140 {
141 if (nyble == finsert && deficit)
142 {
143 dc[dp] = 0;
144 deficit--;
145 }
146 else
147 dc[dp] = d[nyble++];
148 }
149
150 /* Set unused bits to 0... -A1kmm */
151 if (bits < 128 && (bits % 16 != 0))
152 dc[bits / 16] &= ~((1 << (15 - bits % 16)) - 1);
153 for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; ++dp)
154 dc[dp] = 0;
155
156 /* And assign... -A1kmm */
157 if (addr)
158 for (dp = 0; dp < 8; ++dp)
159 /* The cast is a kludge to make netbsd work. */
160 ((unsigned short *)&v6->sin6_addr)[dp] = htons(dc[dp]);
161
162 if (b)
163 *b = bits;
164 return HM_IPV6;
165 }
166
167 /* int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
168 * Input: A possible IPV4 address as a string.
169 * Output: An integer describing whether it is an IPV4 or hostmask,
170 * an address(if it is IPV4), a bitlength(if it is IPV4).
171 * Side effects: None
172 * Comments: Called from parse_netmask
173 */
174 static int
175 try_parse_v4_netmask(const char *text, struct irc_ssaddr *addr, int *b)
176 {
177 const char *digits[4];
178 unsigned char addb[4];
179 int n = 0, bits = 0;
180 char c;
181 struct sockaddr_in *const v4 = (struct sockaddr_in *)addr;
182
183 digits[n++] = text;
184
185 for (const char *p = text; (c = *p); ++p)
186 {
187 if (c >= '0' && c <= '9') /* empty */
188 ;
189 else if (c == '.')
190 {
191 if (n >= 4)
192 return HM_HOST;
193
194 digits[n++] = p + 1;
195 }
196 else if (c == '*')
197 {
198 if (*(p + 1) || n == 0 || *(p - 1) != '.')
199 return HM_HOST;
200
201 bits = (n - 1) * 8;
202 break;
203 }
204 else if (c == '/')
205 {
206 char *after;
207 bits = strtoul(p + 1, &after, 10);
208
209 if (bits < 0 || *after)
210 return HM_HOST;
211 if (bits > n * 8)
212 return HM_HOST;
213
214 break;
215 }
216 else
217 return HM_HOST;
218 }
219
220 if (n < 4 && bits == 0)
221 bits = n * 8;
222 if (bits)
223 while (n < 4)
224 digits[n++] = "0";
225
226 for (n = 0; n < 4; ++n)
227 addb[n] = strtoul(digits[n], NULL, 10);
228
229 if (bits == 0)
230 bits = 32;
231
232 /* Set unused bits to 0... -A1kmm */
233 if (bits < 32 && bits % 8)
234 addb[bits / 8] &= ~((1 << (8 - bits % 8)) - 1);
235 for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; ++n)
236 addb[n] = 0;
237 if (addr)
238 v4->sin_addr.s_addr =
239 htonl(addb[0] << 24 | addb[1] << 16 | addb[2] << 8 | addb[3]);
240 if (b)
241 *b = bits;
242 return HM_IPV4;
243 }
244
245 /* int parse_netmask(const char *, struct irc_ssaddr *, int *);
246 * Input: A hostmask, or an IPV4/6 address.
247 * Output: An integer describing whether it is an IPV4, IPV6 address or a
248 * hostmask, an address(if it is an IP mask),
249 * a bitlength(if it is IP mask).
250 * Side effects: None
251 */
252 int
253 parse_netmask(const char *text, struct irc_ssaddr *addr, int *b)
254 {
255 if (strchr(text, '.'))
256 return try_parse_v4_netmask(text, addr, b);
257 if (strchr(text, ':'))
258 return try_parse_v6_netmask(text, addr, b);
259
260 return HM_HOST;
261 }
262
263 /* The address matching stuff... */
264 /* int match_ipv6(struct irc_ssaddr *, struct irc_ssaddr *, int)
265 * Input: An IP address, an IP mask, the number of bits in the mask.
266 * Output: if match, -1 else 0
267 * Side effects: None
268 */
269 int
270 match_ipv6(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
271 {
272 int i, m, n = bits / 8;
273 const struct sockaddr_in6 *const v6 = (const struct sockaddr_in6 *)addr;
274 const struct sockaddr_in6 *const v6mask = (const struct sockaddr_in6 *)mask;
275
276 for (i = 0; i < n; ++i)
277 if (v6->sin6_addr.s6_addr[i] != v6mask->sin6_addr.s6_addr[i])
278 return 0;
279
280 if ((m = bits % 8) == 0)
281 return -1;
282 if ((v6->sin6_addr.s6_addr[n] & ~((1 << (8 - m)) - 1)) ==
283 v6mask->sin6_addr.s6_addr[n])
284 return -1;
285 return 0;
286 }
287
288 /* int match_ipv4(struct irc_ssaddr *, struct irc_ssaddr *, int)
289 * Input: An IP address, an IP mask, the number of bits in the mask.
290 * Output: if match, -1 else 0
291 * Side Effects: None
292 */
293 int
294 match_ipv4(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
295 {
296 const struct sockaddr_in *const v4 = (const struct sockaddr_in *)addr;
297 const struct sockaddr_in *const v4mask = (const struct sockaddr_in *)mask;
298
299 if ((ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1)) !=
300 ntohl(v4mask->sin_addr.s_addr))
301 return 0;
302 return -1;
303 }
304
305 /*
306 * mask_addr
307 *
308 * inputs - pointer to the ip to mask
309 * - bitlen
310 * output - NONE
311 * side effects -
312 */
313 void
314 mask_addr(struct irc_ssaddr *ip, int bits)
315 {
316 int mask;
317 struct sockaddr_in6 *v6_base_ip;
318 int i, m, n;
319 struct sockaddr_in *v4_base_ip;
320
321 if (ip->ss.ss_family == AF_INET)
322 {
323 uint32_t tmp = 0;
324 v4_base_ip = (struct sockaddr_in *)ip;
325
326 mask = ~((1 << (32 - bits)) - 1);
327 tmp = ntohl(v4_base_ip->sin_addr.s_addr);
328 v4_base_ip->sin_addr.s_addr = htonl(tmp & mask);
329 }
330 else
331 {
332 n = bits / 8;
333 m = bits % 8;
334 v6_base_ip = (struct sockaddr_in6 *)ip;
335
336 mask = ~((1 << (8 - m)) - 1);
337 v6_base_ip->sin6_addr.s6_addr[n] = v6_base_ip->sin6_addr.s6_addr[n] & mask;
338
339 for (i = n + 1; i < 16; i++)
340 v6_base_ip->sin6_addr.s6_addr[i] = 0;
341 }
342 }
343
344 /* unsigned long hash_ipv4(struct irc_ssaddr*)
345 * Input: An IP address.
346 * Output: A hash value of the IP address.
347 * Side effects: None
348 */
349 static uint32_t
350 hash_ipv4(const struct irc_ssaddr *addr, int bits)
351 {
352 if (bits != 0)
353 {
354 const struct sockaddr_in *const v4 = (const struct sockaddr_in *)addr;
355 uint32_t av = ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1);
356
357 return (av ^ (av >> 12) ^ (av >> 24)) & (ATABLE_SIZE - 1);
358 }
359
360 return 0;
361 }
362
363 /* unsigned long hash_ipv6(struct irc_ssaddr*)
364 * Input: An IP address.
365 * Output: A hash value of the IP address.
366 * Side effects: None
367 */
368 static uint32_t
369 hash_ipv6(const struct irc_ssaddr *addr, int bits)
370 {
371 uint32_t v = 0, n;
372 const struct sockaddr_in6 *const v6 = (const struct sockaddr_in6 *)addr;
373
374 for (n = 0; n < 16; ++n)
375 {
376 if (bits >= 8)
377 {
378 v ^= v6->sin6_addr.s6_addr[n];
379 bits -= 8;
380 }
381 else if (bits)
382 {
383 v ^= v6->sin6_addr.s6_addr[n] & ~((1 << (8 - bits)) - 1);
384 return v & (ATABLE_SIZE - 1);
385 }
386 else
387 return v & (ATABLE_SIZE - 1);
388 }
389
390 return v & (ATABLE_SIZE - 1);
391 }
392
393 /* int hash_text(const char *start)
394 * Input: The start of the text to hash.
395 * Output: The hash of the string between 1 and (TH_MAX-1)
396 * Side-effects: None.
397 */
398 static uint32_t
399 hash_text(const char *start)
400 {
401 uint32_t h = 0;
402
403 for (const char *p = start; *p; ++p)
404 h = (h << 4) - (h + ToLower(*p));
405
406 return h & (ATABLE_SIZE - 1);
407 }
408
409 /* unsigned long get_hash_mask(const char *)
410 * Input: The text to hash.
411 * Output: The hash of the string right of the first '.' past the last
412 * wildcard in the string.
413 * Side-effects: None.
414 */
415 static uint32_t
416 get_mask_hash(const char *text)
417 {
418 const char *hp = "", *p;
419
420 for (p = text + strlen(text) - 1; p >= text; --p)
421 if (IsMWildChar(*p))
422 return hash_text(hp);
423 else if (*p == '.')
424 hp = p + 1;
425 return hash_text(text);
426 }
427
428 /* struct MaskItem *find_conf_by_address(const char *, struct irc_ssaddr *,
429 * int type, int fam, const char *username)
430 * Input: The hostname, the address, the type of mask to find, the address
431 * family, the username.
432 * Output: The matching value with the highest precedence.
433 * Side-effects: None
434 * Note: Setting bit 0 of the type means that the username is ignored.
435 * Warning: IsNeedPassword for everything that is not an auth{} entry
436 * should always be true (i.e. conf->flags & CONF_FLAGS_NEED_PASSWORD == 0)
437 */
438 struct MaskItem *
439 find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int type,
440 int fam, const char *username, const char *password, int do_match)
441 {
442 unsigned int hprecv = 0;
443 dlink_node *node = NULL;
444 struct MaskItem *hprec = NULL;
445 struct AddressRec *arec = NULL;
446 int b;
447 int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
448
449 if (addr)
450 {
451 /* Check for IPV6 matches... */
452 if (fam == AF_INET6)
453 {
454 for (b = 128; b >= 0; b -= 16)
455 {
456 DLINK_FOREACH(node, atable[hash_ipv6(addr, b)].head)
457 {
458 arec = node->data;
459
460 if ((arec->type == type) &&
461 arec->precedence > hprecv &&
462 arec->masktype == HM_IPV6 &&
463 match_ipv6(addr, &arec->Mask.ipa.addr,
464 arec->Mask.ipa.bits) &&
465 (!username || !cmpfunc(arec->username, username)) &&
466 (IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
467 match_conf_password(password, arec->conf)))
468 {
469 hprecv = arec->precedence;
470 hprec = arec->conf;
471 }
472 }
473 }
474 }
475 else if (fam == AF_INET)
476 {
477 for (b = 32; b >= 0; b -= 8)
478 {
479 DLINK_FOREACH(node, atable[hash_ipv4(addr, b)].head)
480 {
481 arec = node->data;
482
483 if ((arec->type == type) &&
484 arec->precedence > hprecv &&
485 arec->masktype == HM_IPV4 &&
486 match_ipv4(addr, &arec->Mask.ipa.addr,
487 arec->Mask.ipa.bits) &&
488 (!username || !cmpfunc(arec->username, username)) &&
489 (IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
490 match_conf_password(password, arec->conf)))
491 {
492 hprecv = arec->precedence;
493 hprec = arec->conf;
494 }
495 }
496 }
497 }
498 }
499
500 if (name)
501 {
502 const char *p = name;
503
504 while (1)
505 {
506 DLINK_FOREACH(node, atable[hash_text(p)].head)
507 {
508 arec = node->data;
509 if ((arec->type == type) &&
510 arec->precedence > hprecv &&
511 (arec->masktype == HM_HOST) &&
512 !cmpfunc(arec->Mask.hostname, name) &&
513 (!username || !cmpfunc(arec->username, username)) &&
514 (IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
515 match_conf_password(password, arec->conf)))
516 {
517 hprecv = arec->precedence;
518 hprec = arec->conf;
519 }
520 }
521
522 if ((p = strchr(p, '.')) == NULL)
523 break;
524 ++p;
525 }
526
527 DLINK_FOREACH(node, atable[0].head)
528 {
529 arec = node->data;
530
531 if (arec->type == type &&
532 arec->precedence > hprecv &&
533 arec->masktype == HM_HOST &&
534 !cmpfunc(arec->Mask.hostname, name) &&
535 (!username || !cmpfunc(arec->username, username)) &&
536 (IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
537 match_conf_password(password, arec->conf)))
538 {
539 hprecv = arec->precedence;
540 hprec = arec->conf;
541 }
542 }
543 }
544
545 return hprec;
546 }
547
548 /* struct MaskItem* find_address_conf(const char*, const char*,
549 * struct irc_ssaddr*, int, char *);
550 * Input: The hostname, username, address, address family.
551 * Output: The applicable MaskItem.
552 * Side-effects: None
553 */
554 struct MaskItem *
555 find_address_conf(const char *host, const char *user, struct irc_ssaddr *ip,
556 int aftype, const char *password)
557 {
558 struct MaskItem *authcnf = NULL, *killcnf = NULL;
559
560 /* Find the best auth{} block... If none, return NULL -A1kmm */
561 if ((authcnf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user,
562 password, 1)) == NULL)
563 return NULL;
564
565 /* If they are exempt from K-lines, return the best auth{} block. -A1kmm */
566 if (IsConfExemptKline(authcnf))
567 return authcnf;
568
569 /* Find the best K-line... -A1kmm */
570 killcnf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
571
572 /*
573 * If they are K-lined, return the K-line. Otherwise, return the
574 * auth {} block. -A1kmm
575 */
576 if (killcnf)
577 return killcnf;
578
579 return authcnf;
580 }
581
582 /* struct MaskItem* find_dline_conf(struct irc_ssaddr*, int)
583 *
584 * Input: An address, an address family.
585 * Output: The best matching D-line or exempt line.
586 * Side effects: None.
587 */
588 struct MaskItem *
589 find_dline_conf(struct irc_ssaddr *addr, int aftype)
590 {
591 struct MaskItem *eline;
592
593 eline = find_conf_by_address(NULL, addr, CONF_EXEMPT, aftype, NULL, NULL, 1);
594 if (eline)
595 return eline;
596
597 return find_conf_by_address(NULL, addr, CONF_DLINE, aftype, NULL, NULL, 1);
598 }
599
600 /* void add_conf_by_address(int, struct MaskItem *aconf)
601 * Input:
602 * Output: None
603 * Side-effects: Adds this entry to the hash table.
604 */
605 struct AddressRec *
606 add_conf_by_address(const unsigned int type, struct MaskItem *conf)
607 {
608 struct AddressRec *arec = NULL;
609 const char *const hostname = conf->host;
610 const char *const username = conf->user;
611 static unsigned int prec_value = 0xFFFFFFFF;
612 int bits = 0;
613
614 assert(type && !EmptyString(hostname));
615
616 arec = MyCalloc(sizeof(struct AddressRec));
617 arec->masktype = parse_netmask(hostname, &arec->Mask.ipa.addr, &bits);
618 arec->Mask.ipa.bits = bits;
619 arec->username = username;
620 arec->conf = conf;
621 arec->precedence = prec_value--;
622 arec->type = type;
623
624 switch (arec->masktype)
625 {
626 case HM_IPV4:
627 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
628 bits -= bits % 8;
629 dlinkAdd(arec, &arec->node, &atable[hash_ipv4(&arec->Mask.ipa.addr, bits)]);
630 break;
631 case HM_IPV6:
632 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
633 bits -= bits % 16;
634 dlinkAdd(arec, &arec->node, &atable[hash_ipv6(&arec->Mask.ipa.addr, bits)]);
635 break;
636 default: /* HM_HOST */
637 arec->Mask.hostname = hostname;
638 dlinkAdd(arec, &arec->node, &atable[get_mask_hash(hostname)]);
639 break;
640 }
641
642 return arec;
643 }
644
645 /* void delete_one_address(const char*, struct MaskItem*)
646 * Input: An address string, the associated MaskItem.
647 * Output: None
648 * Side effects: Deletes an address record. Frees the MaskItem if there
649 * is nothing referencing it, sets it as illegal otherwise.
650 */
651 void
652 delete_one_address_conf(const char *address, struct MaskItem *conf)
653 {
654 int bits = 0;
655 uint32_t hv = 0;
656 dlink_node *node = NULL;
657 struct irc_ssaddr addr;
658
659 switch (parse_netmask(address, &addr, &bits))
660 {
661 case HM_IPV4:
662 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
663 bits -= bits % 8;
664 hv = hash_ipv4(&addr, bits);
665 break;
666 case HM_IPV6:
667 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
668 bits -= bits % 16;
669 hv = hash_ipv6(&addr, bits);
670 break;
671 default: /* HM_HOST */
672 hv = get_mask_hash(address);
673 break;
674 }
675
676 DLINK_FOREACH(node, atable[hv].head)
677 {
678 struct AddressRec *arec = node->data;
679
680 if (arec->conf == conf)
681 {
682 dlinkDelete(&arec->node, &atable[hv]);
683
684 if (!conf->ref_count)
685 conf_free(conf);
686
687 MyFree(arec);
688 return;
689 }
690 }
691 }
692
693 /* void clear_out_address_conf(void)
694 * Input: None
695 * Output: None
696 * Side effects: Clears out all address records in the hash table,
697 * frees them, and frees the MaskItems if nothing references
698 * them, otherwise sets them as illegal.
699 */
700 void
701 clear_out_address_conf(void)
702 {
703 dlink_node *node = NULL, *node_next = NULL;
704
705 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
706 {
707 DLINK_FOREACH_SAFE(node, node_next, atable[i].head)
708 {
709 struct AddressRec *arec = node->data;
710
711 /*
712 * Destroy the ircd.conf items and keep those that are in the databases
713 */
714 if (IsConfDatabase(arec->conf))
715 continue;
716
717 dlinkDelete(&arec->node, &atable[i]);
718 arec->conf->active = 0;
719
720 if (!arec->conf->ref_count)
721 conf_free(arec->conf);
722 MyFree(arec);
723 }
724 }
725 }
726
727 static void
728 hostmask_send_expiration(const struct AddressRec *const arec)
729 {
730 char ban_type = '\0';
731
732 if (!ConfigGeneral.tkline_expire_notices)
733 return;
734
735 switch (arec->type)
736 {
737 case CONF_KLINE:
738 ban_type = 'K';
739 break;
740 case CONF_DLINE:
741 ban_type = 'D';
742 break;
743 default: break;
744 }
745
746 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
747 "Temporary %c-line for [%s@%s] expired", ban_type,
748 (arec->conf->user) ? arec->conf->user : "*",
749 (arec->conf->host) ? arec->conf->host : "*");
750 }
751
752 void
753 hostmask_expire_temporary(void)
754 {
755 dlink_node *node = NULL, *node_next = NULL;
756
757 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
758 {
759 DLINK_FOREACH_SAFE(node, node_next, atable[i].head)
760 {
761 struct AddressRec *arec = node->data;
762
763 if (!arec->conf->until || arec->conf->until > CurrentTime)
764 continue;
765
766 switch (arec->type)
767 {
768 case CONF_KLINE:
769 case CONF_DLINE:
770 hostmask_send_expiration(arec);
771
772 dlinkDelete(&arec->node, &atable[i]);
773 conf_free(arec->conf);
774 MyFree(arec);
775 break;
776 default: break;
777 }
778 }
779 }
780 }

Properties

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