ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hostmask.c
Revision: 7791
Committed: Mon Oct 17 17:30:58 2016 UTC (8 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 20662 byte(s)
Log Message:
- hostmask.c: try_parse_v6_netmask()/try_parse_v4_netmask(): set address family accordingly. parse_netmask(): zero out 'addr'

File Contents

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

Properties

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