ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hostmask.c
Revision: 6579
Committed: Mon Oct 19 19:10:05 2015 UTC (9 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 20522 byte(s)
Log Message:
- hostmask.c: removed irrelevant comment

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

Properties

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