ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hostmask.c
(Generate patch)

Comparing:
ircd-hybrid/src/hostmask.c (file contents), Revision 33 by knight, Sun Oct 2 20:50:00 2005 UTC vs.
ircd-hybrid/trunk/src/hostmask.c (file contents), Revision 4977 by michael, Thu Dec 4 15:12:24 2014 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  hostmask.c: Code to efficiently find IP & hostmask based configs.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2005 by the past and present ircd coders, and others.
4 > *  Copyright (c) 2001-2014 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
# Line 16 | Line 15
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
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 "tools.h"
31 < #include "s_conf.h"
30 > #include "list.h"
31 > #include "conf.h"
32   #include "hostmask.h"
31 – #include "numeric.h"
33   #include "send.h"
34   #include "irc_string.h"
35 + #include "ircd.h"
36  
35 – #ifdef IPV6
36 – static int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *);
37 – static unsigned long hash_ipv6(struct irc_ssaddr *, int);
38 – #endif
39 – static int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
40 – static unsigned long hash_ipv4(struct irc_ssaddr *, int);
37  
38   #define DigitParse(ch) do { \
39                         if (ch >= '0' && ch <= '9') \
# Line 46 | Line 42 | static unsigned long hash_ipv4(struct ir
42                           ch = ch - 'A' + 10; \
43                         else if (ch >= 'a' && ch <= 'f') \
44                           ch = ch - 'a' + 10; \
45 <                       } while(0);
45 >                       } while (0);
46  
47   /* The mask parser/type determination code... */
48  
# Line 57 | Line 53 | static unsigned long hash_ipv4(struct ir
53   * Side effects: None
54   * Comments: Called from parse_netmask
55   */
56 < /* Fixed so ::/0 (any IPv6 address) is valid
56 > /* Fixed so ::/0 (any IPv6 address) is valid
57     Also a bug in DigitParse above.
58     -Gozem 2002-07-19 gozem@linux.nu
59   */
64 – #ifdef IPV6
60   static int
61   try_parse_v6_netmask(const char *text, struct irc_ssaddr *addr, int *b)
62   {
68 –  const char *p;
63    char c;
64    int d[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
65    int dp = 0;
# Line 74 | Line 68 | try_parse_v6_netmask(const char *text, s
68    int bits = 128;
69    int deficit = 0;
70    short dc[8];
71 <  struct sockaddr_in6 *v6 = (struct sockaddr_in6*) addr;
71 >  struct sockaddr_in6 *const v6 = (struct sockaddr_in6 *)addr;
72  
73 <  for (p = text; (c = *p); p++)
73 >  for (const char *p = text; (c = *p); ++p)
74 >  {
75      if (IsXDigit(c))
76      {
77        if (nyble == 0)
# Line 114 | Line 109 | try_parse_v6_netmask(const char *text, s
109        char *after;
110  
111        d[dp] = d[dp] >> 4 * nyble;
112 <      dp++;
112 >      ++dp;
113        bits = strtoul(p + 1, &after, 10);
114 +
115        if (bits < 0 || *after)
116          return HM_HOST;
117        if (bits > dp * 4 && !(finsert >= 0 && bits <= 128))
# Line 124 | Line 120 | try_parse_v6_netmask(const char *text, s
120      }
121      else
122        return HM_HOST;
123 +  }
124  
125    d[dp] = d[dp] >> 4 * nyble;
126 +
127    if (c == 0)
128 <    dp++;
128 >    ++dp;
129    if (finsert < 0 && bits == 0)
130      bits = dp * 16;
131 +
132    /* How many words are missing? -A1kmm */
133    deficit = bits / 16 + ((bits % 16) ? 1 : 0) - dp;
134 +
135    /* Now fill in the gaps(from ::) in the copied table... -A1kmm */
136 <  for (dp = 0, nyble = 0; dp < 8; dp++)
136 >  for (dp = 0, nyble = 0; dp < 8; ++dp)
137    {
138      if (nyble == finsert && deficit)
139      {
# Line 143 | Line 143 | try_parse_v6_netmask(const char *text, s
143      else
144        dc[dp] = d[nyble++];
145    }
146 +
147    /* Set unused bits to 0... -A1kmm */
148    if (bits < 128 && (bits % 16 != 0))
149      dc[bits / 16] &= ~((1 << (15 - bits % 16)) - 1);
150 <  for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; dp++)
150 >  for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; ++dp)
151      dc[dp] = 0;
152 +
153    /* And assign... -A1kmm */
154    if (addr)
155 <    for (dp = 0; dp < 8; dp++)
155 >    for (dp = 0; dp < 8; ++dp)
156        /* The cast is a kludge to make netbsd work. */
157        ((unsigned short *)&v6->sin6_addr)[dp] = htons(dc[dp]);
158 <  if (b != NULL)
158 >
159 >  if (b)
160      *b = bits;
161    return HM_IPV6;
162   }
160 – #endif
163  
164   /* int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
165   * Input: A possible IPV4 address as a string.
# Line 169 | Line 171 | try_parse_v6_netmask(const char *text, s
171   static int
172   try_parse_v4_netmask(const char *text, struct irc_ssaddr *addr, int *b)
173   {
172 –  const char *p;
174    const char *digits[4];
175    unsigned char addb[4];
176    int n = 0, bits = 0;
177    char c;
178 <  struct sockaddr_in *v4 = (struct sockaddr_in*) addr;
178 >  struct sockaddr_in *const v4 = (struct sockaddr_in *)addr;
179  
180    digits[n++] = text;
181  
182 <  for (p = text; (c = *p); p++)
182 >  for (const char *p = text; (c = *p); ++p)
183 >  {
184      if (c >= '0' && c <= '9')   /* empty */
185        ;
186      else if (c == '.')
187      {
188        if (n >= 4)
189          return HM_HOST;
190 +
191        digits[n++] = p + 1;
192      }
193      else if (c == '*')
194      {
195        if (*(p + 1) || n == 0 || *(p - 1) != '.')
196          return HM_HOST;
197 +
198        bits = (n - 1) * 8;
199        break;
200      }
# Line 198 | Line 202 | try_parse_v4_netmask(const char *text, s
202      {
203        char *after;
204        bits = strtoul(p + 1, &after, 10);
205 <      if (!bits || *after)
205 >
206 >      if (bits < 0 || *after)
207          return HM_HOST;
208        if (bits > n * 8)
209          return HM_HOST;
210 +
211        break;
212      }
213      else
214        return HM_HOST;
215 +  }
216  
217    if (n < 4 && bits == 0)
218      bits = n * 8;
219    if (bits)
220      while (n < 4)
221        digits[n++] = "0";
222 <  for (n = 0; n < 4; n++)
222 >
223 >  for (n = 0; n < 4; ++n)
224      addb[n] = strtoul(digits[n], NULL, 10);
225 +
226    if (bits == 0)
227      bits = 32;
228 +
229    /* Set unused bits to 0... -A1kmm */
230    if (bits < 32 && bits % 8)
231      addb[bits / 8] &= ~((1 << (8 - bits % 8)) - 1);
232 <  for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; n++)
232 >  for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; ++n)
233      addb[n] = 0;
234    if (addr)
235      v4->sin_addr.s_addr =
236        htonl(addb[0] << 24 | addb[1] << 16 | addb[2] << 8 | addb[3]);
237 <  if (b != NULL)
237 >  if (b)
238      *b = bits;
239    return HM_IPV4;
240   }
# Line 239 | Line 249 | try_parse_v4_netmask(const char *text, s
249   int
250   parse_netmask(const char *text, struct irc_ssaddr *addr, int *b)
251   {
242 – #ifdef IPV6
243 –    if (strchr(text, ':'))
244 –    return try_parse_v6_netmask(text, addr, b);
245 – #endif
252    if (strchr(text, '.'))
253      return try_parse_v4_netmask(text, addr, b);
254 +  if (strchr(text, ':'))
255 +    return try_parse_v6_netmask(text, addr, b);
256 +
257    return HM_HOST;
258   }
259  
# Line 254 | Line 263 | parse_netmask(const char *text, struct i
263   * Output: if match, -1 else 0
264   * Side effects: None
265   */
257 – #ifdef IPV6
266   int
267 < match_ipv6(struct irc_ssaddr *addr, struct irc_ssaddr *mask, int bits)
267 > match_ipv6(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
268   {
269    int i, m, n = bits / 8;
270 <  struct sockaddr_in6 *v6 = (struct sockaddr_in6*)addr;
271 <  struct sockaddr_in6 *v6mask = (struct sockaddr_in6*)mask;
270 >  const struct sockaddr_in6 *const v6 = (const struct sockaddr_in6 *)addr;
271 >  const struct sockaddr_in6 *const v6mask = (const struct sockaddr_in6 *)mask;
272  
273 <  for (i = 0; i < n; i++)
273 >  for (i = 0; i < n; ++i)
274      if (v6->sin6_addr.s6_addr[i] != v6mask->sin6_addr.s6_addr[i])
275        return 0;
276 +
277    if ((m = bits % 8) == 0)
278      return -1;
279    if ((v6->sin6_addr.s6_addr[n] & ~((1 << (8 - m)) - 1)) ==
# Line 272 | Line 281 | match_ipv6(struct irc_ssaddr *addr, stru
281      return -1;
282    return 0;
283   }
284 < #endif
284 >
285   /* int match_ipv4(struct irc_ssaddr *, struct irc_ssaddr *, int)
286   * Input: An IP address, an IP mask, the number of bits in the mask.
287   * Output: if match, -1 else 0
288   * Side Effects: None
289   */
290   int
291 < match_ipv4(struct irc_ssaddr *addr, struct irc_ssaddr *mask, int bits)
291 > match_ipv4(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
292   {
293 <  struct sockaddr_in *v4 = (struct sockaddr_in*) addr;
294 <  struct sockaddr_in *v4mask = (struct sockaddr_in*) mask;
293 >  const struct sockaddr_in *const v4 = (const struct sockaddr_in *)addr;
294 >  const struct sockaddr_in *const v4mask = (const struct sockaddr_in *)mask;
295 >
296    if ((ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1)) !=
297        ntohl(v4mask->sin_addr.s_addr))
298      return 0;
# Line 301 | Line 311 | void
311   mask_addr(struct irc_ssaddr *ip, int bits)
312   {
313    int mask;
304 – #ifdef IPV6
314    struct sockaddr_in6 *v6_base_ip;
315    int i, m, n;
307 – #endif
316    struct sockaddr_in *v4_base_ip;
317  
318 < #ifdef IPV6
311 <  if (ip->ss.ss_family != AF_INET6)
312 < #endif
318 >  if (ip->ss.ss_family == AF_INET)
319    {
320 <    v4_base_ip = (struct sockaddr_in*)ip;
320 >    uint32_t tmp = 0;
321 >    v4_base_ip = (struct sockaddr_in *)ip;
322 >
323      mask = ~((1 << (32 - bits)) - 1);
324 <    v4_base_ip->sin_addr.s_addr =
325 <      htonl(ntohl(v4_base_ip->sin_addr.s_addr) & mask);
324 >    tmp = ntohl(v4_base_ip->sin_addr.s_addr);
325 >    v4_base_ip->sin_addr.s_addr = htonl(tmp & mask);
326    }
319 – #ifdef IPV6
327    else
328    {
329      n = bits / 8;
330      m = bits % 8;
331 <    v6_base_ip = (struct sockaddr_in6*)ip;
331 >    v6_base_ip = (struct sockaddr_in6 *)ip;
332  
333 <    mask = ~((1 << (8 - m)) -1 );
333 >    mask = ~((1 << (8 - m)) - 1);
334      v6_base_ip->sin6_addr.s6_addr[n] = v6_base_ip->sin6_addr.s6_addr[n] & mask;
335 <    for (i = n + 1; n < 16; i++)
336 <      v6_base_ip->sin6_addr.s6_addr[n] = 0;
335 >
336 >    for (i = n + 1; i < 16; i++)
337 >      v6_base_ip->sin6_addr.s6_addr[i] = 0;
338    }
331 – #endif
339   }
340  
341 < /* Hashtable stuff...now external as its used in m_stats.c */
342 < struct AddressRec *atable[ATABLE_SIZE];
336 <
337 < void
338 < init_host_hash(void)
339 < {
340 <  memset(&atable, 0, sizeof(atable));
341 < }
341 > /* Hashtable stuff...now external as it's used in m_stats.c */
342 > dlink_list atable[ATABLE_SIZE];
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 unsigned long
350 < hash_ipv4(struct irc_ssaddr *addr, int bits)
349 > static uint32_t
350 > hash_ipv4(const struct irc_ssaddr *addr, int bits)
351   {
352    if (bits != 0)
353    {
354 <    struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
355 <    unsigned long av = ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1);
356 <    return((av ^ (av >> 12) ^ (av >> 24)) & (ATABLE_SIZE - 1));
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);
360 >  return 0;
361   }
362  
363   /* unsigned long hash_ipv6(struct irc_ssaddr*)
# Line 363 | Line 365 | hash_ipv4(struct irc_ssaddr *addr, int b
365   * Output: A hash value of the IP address.
366   * Side effects: None
367   */
368 < #ifdef IPV6
369 < static unsigned long
370 < hash_ipv6(struct irc_ssaddr *addr, int bits)
371 < {
372 <  unsigned long v = 0, n;
373 <  struct sockaddr_in6 *v6 = (struct sockaddr_in6*) addr;
374 <  
373 <  for (n = 0; n < 16; n++)
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      {
# Line 385 | Line 386 | hash_ipv6(struct irc_ssaddr *addr, int b
386      else
387        return v & (ATABLE_SIZE - 1);
388    }
389 +
390    return v & (ATABLE_SIZE - 1);
391   }
390 – #endif
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 int
398 > static uint32_t
399   hash_text(const char *start)
400   {
401 <  const char *p = start;
401 <  unsigned long h = 0;
401 >  uint32_t h = 0;
402  
403 <  while (*p)
404 <  {
405 <    h = (h << 4) - (h + (unsigned char)ToLower(*p++));
406 <  }
407 <  return (h & (ATABLE_SIZE - 1));
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 *)
# Line 413 | Line 412 | hash_text(const char *start)
412   *         wildcard in the string.
413   * Side-effects: None.
414   */
415 < static unsigned long
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 (*p == '*' || *p == '?')
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 AccessItem *find_conf_by_address(const char *, struct irc_ssaddr *,
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.
# Line 434 | Line 433 | get_mask_hash(const char *text)
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. aconf->flags & CONF_FLAGS_NEED_PASSWORD == 0)
436 > * should always be true (i.e. conf->flags & CONF_FLAGS_NEED_PASSWORD == 0)
437   */
438 < struct AccessItem *
439 < find_conf_by_address(const char *name, struct irc_ssaddr *addr, int type,
440 <                     int fam, const char *username, const char *password)
441 < {
442 <  unsigned long hprecv = 0;
443 <  struct AccessItem *hprec = NULL;
444 <  struct AddressRec *arec;
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 <
448 <  if (username == NULL)
449 <    username = "";
450 <  if (password == NULL)
451 <    password = "";
447 >  int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
448  
449    if (addr)
450    {
451      /* Check for IPV6 matches... */
456 – #ifdef IPV6
452      if (fam == AF_INET6)
453      {
454        for (b = 128; b >= 0; b -= 16)
455        {
456 <        for (arec = atable[hash_ipv6(addr, b)]; arec; arec = arec->next)
457 <          if (arec->type == (type & ~0x1) &&
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 <              (type & 0x1 || match(arec->username, username)) &&
466 <              (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
467 <               match_conf_password(password, arec->aconf)))
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->aconf;
470 >            hprec = arec->conf;
471            }
472 +        }
473        }
474      }
475 <    else
477 < #endif
478 <    if (fam == AF_INET)
475 >    else if (fam == AF_INET)
476      {
477        for (b = 32; b >= 0; b -= 8)
478        {
479 <        for (arec = atable[hash_ipv4(addr, b)]; arec; arec = arec->next)
480 <          if (arec->type == (type & ~0x1) &&
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 <              (type & 0x1 || match(arec->username, username)) &&
489 <              (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
490 <               match_conf_password(password, arec->aconf)))
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->aconf;
493 >            hprec = arec->conf;
494            }
495 +        }
496        }
497      }
498    }
499  
500 <  if (name != NULL)
500 >  if (name)
501    {
502      const char *p = name;
503  
504      while (1)
505      {
506 <      for (arec = atable[hash_text(p)]; arec != NULL; arec = arec->next)
507 <        if ((arec->type == (type & ~0x1)) &&
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 <            match(arec->Mask.hostname, name) &&
513 <            (type & 0x1 || match(arec->username, username)) &&
514 <            (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
515 <             match_conf_password(password, arec->aconf)))
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->aconf;
518 >          hprec = arec->conf;
519          }
520 <      p = strchr(p, '.');
521 <      if (p == NULL)
520 >      }
521 >
522 >      if ((p = strchr(p, '.')) == NULL)
523          break;
524 <      p++;
524 >      ++p;
525      }
526 <    for (arec = atable[0]; arec; arec = arec->next)
527 <      if (arec->type == (type & ~0x1) &&
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 <          match(arec->Mask.hostname, name) &&
535 <          (type & 0x1 || match(arec->username, username)) &&
536 <          (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
537 <           match_conf_password(password, arec->aconf)))
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->aconf;
540 >        hprec = arec->conf;
541        }
542 +    }
543    }
544  
545    return hprec;
546   }
547  
548 < /* struct AccessItem* find_address_conf(const char*, const char*,
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 AccessItem.
551 > * Output: The applicable MaskItem.
552   * Side-effects: None
553   */
554 < struct AccessItem *
555 < find_address_conf(const char *host, const char *user,
556 <                  struct irc_ssaddr *ip, int aftype, char *password)
557 < {
558 <  struct AccessItem *iconf, *kconf;
559 <
560 <  /* Find the best I-line... If none, return NULL -A1kmm */
561 <  if ((iconf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user,
562 <                                    password)) == NULL)
563 <    return(NULL);
564 <
565 <  /* If they are exempt from K-lines, return the best I-line. -A1kmm */
566 <  if (IsConfExemptKline(iconf))
567 <    return(iconf);
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 <  kconf = find_conf_by_address(host, ip, CONF_KILL, aftype, user, NULL);
570 >  killcnf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
571  
572 <  /* If they are K-lined, return the K-line. Otherwise, return the
573 <   * I-line. -A1kmm */
574 <  if (kconf != NULL)
575 <    return(kconf);
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 <  kconf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL);
580 <  if (kconf != NULL && !IsConfExemptGline(iconf))
570 <    return(kconf);
571 <
572 <  return(iconf);
573 < }
574 <
575 < struct AccessItem *
576 < find_gline_conf(const char *host, const char *user,
577 <                struct irc_ssaddr *ip, int aftype)
578 < {
579 <  struct AccessItem *eline;
580 <
581 <  eline = find_conf_by_address(host, ip, CONF_EXEMPTKLINE, aftype,
582 <                               user, NULL);
583 <  if (eline != NULL)
584 <    return(eline);
585 <
586 <  return(find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL));
587 < }
588 <
589 < /* find_kline_conf
590 < *
591 < * inputs       - pointer to hostname
592 < *              - pointer to username
593 < *              - incoming IP and type (IPv4 vs. IPv6)
594 < * outut        - pointer to kline conf if found NULL if not
595 < * side effects -
596 < */
597 < struct AccessItem *
598 < find_kline_conf(const char *host, const char *user,
599 <                struct irc_ssaddr *ip, int aftype)
600 < {
601 <  struct AccessItem *eline;
579 >  if (IsConfExemptGline(authcnf))
580 >    return authcnf;
581  
582 <  eline = find_conf_by_address(host, ip, CONF_EXEMPTKLINE, aftype,
583 <                               user, NULL);
584 <  if (eline != NULL)
606 <    return(eline);
582 >  killcnf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1);
583 >  if (killcnf)
584 >    return killcnf;
585  
586 <  return(find_conf_by_address(host, ip, CONF_KILL, aftype, user, NULL));
586 >  return authcnf;
587   }
588  
589 < /* struct AccessItem* find_dline_conf(struct irc_ssaddr*, int)
589 > /* struct MaskItem* find_dline_conf(struct irc_ssaddr*, int)
590   *
591   * Input:       An address, an address family.
592   * Output:      The best matching D-line or exempt line.
593   * Side effects: None.
594   */
595 < struct AccessItem *
595 > struct MaskItem *
596   find_dline_conf(struct irc_ssaddr *addr, int aftype)
597   {
598 <  struct AccessItem *eline;
598 >  struct MaskItem *eline;
599 >
600 >  eline = find_conf_by_address(NULL, addr, CONF_EXEMPT, aftype, NULL, NULL, 1);
601 >  if (eline)
602 >    return eline;
603  
604 <  eline = find_conf_by_address(NULL, addr, CONF_EXEMPTDLINE | 1, aftype,
623 <                               NULL, NULL);
624 <  if (eline != NULL)
625 <    return(eline);
626 <  return(find_conf_by_address(NULL, addr, CONF_DLINE | 1, aftype, NULL, NULL));
604 >  return find_conf_by_address(NULL, addr, CONF_DLINE, aftype, NULL, NULL, 1);
605   }
606  
607 < /* void add_conf_by_address(int, struct AccessItem *aconf)
608 < * Input:
607 > /* void add_conf_by_address(int, struct MaskItem *aconf)
608 > * Input:
609   * Output: None
610   * Side-effects: Adds this entry to the hash table.
611   */
612 < void
613 < add_conf_by_address(int type, struct AccessItem *aconf)
612 > struct AddressRec *
613 > add_conf_by_address(const unsigned int type, struct MaskItem *conf)
614   {
615 <  const char *address;
616 <  const char *username;
617 <  static unsigned long prec_value = 0xFFFFFFFF;
618 <  int masktype, bits;
619 <  unsigned long hv;
642 <  struct AddressRec *arec;
643 <
644 <  address = aconf->host;
645 <  username = aconf->user;
646 <
647 <  assert(type != 0);
648 <  assert(aconf != NULL);
615 >  struct AddressRec *arec = NULL;
616 >  const char *const hostname = conf->host;
617 >  const char *const username = conf->user;
618 >  static unsigned int prec_value = 0xFFFFFFFF;
619 >  int bits = 0;
620  
621 <  if (EmptyString(address))
651 <    address = "/NOMATCH!/";
621 >  assert(type && !EmptyString(hostname));
622  
623 <  arec = MyMalloc(sizeof(struct AddressRec));
624 <  masktype = parse_netmask(address, &arec->Mask.ipa.addr, &bits);
623 >  arec = MyCalloc(sizeof(struct AddressRec));
624 >  arec->masktype = parse_netmask(hostname, &arec->Mask.ipa.addr, &bits);
625    arec->Mask.ipa.bits = bits;
656 –  arec->masktype = masktype;
657 – #ifdef IPV6
658 –  if (masktype == HM_IPV6)
659 –  {
660 –    /* We have to do this, since we do not re-hash for every bit -A1kmm. */
661 –    bits -= bits % 16;
662 –    arec->next = atable[(hv = hash_ipv6(&arec->Mask.ipa.addr, bits))];
663 –    atable[hv] = arec;
664 –  }
665 –  else
666 – #endif
667 –  if (masktype == HM_IPV4)
668 –  {
669 –    /* We have to do this, since we do not re-hash for every bit -A1kmm. */
670 –    bits -= bits % 8;
671 –    arec->next = atable[(hv = hash_ipv4(&arec->Mask.ipa.addr, bits))];
672 –    atable[hv] = arec;
673 –  }
674 –  else
675 –  {
676 –    arec->Mask.hostname = address;
677 –    arec->next = atable[(hv = get_mask_hash(address))];
678 –    atable[hv] = arec;
679 –  }
626    arec->username = username;
627 <  arec->aconf = aconf;
627 >  arec->conf = conf;
628    arec->precedence = prec_value--;
629    arec->type = type;
630 +
631 +  switch (arec->masktype)
632 +  {
633 +    case HM_IPV4:
634 +      /* We have to do this, since we do not re-hash for every bit -A1kmm. */
635 +      bits -= bits % 8;
636 +      dlinkAdd(arec, &arec->node, &atable[hash_ipv4(&arec->Mask.ipa.addr, bits)]);
637 +      break;
638 +    case HM_IPV6:
639 +      /* We have to do this, since we do not re-hash for every bit -A1kmm. */
640 +      bits -= bits % 16;
641 +      dlinkAdd(arec, &arec->node, &atable[hash_ipv6(&arec->Mask.ipa.addr, bits)]);
642 +      break;
643 +    default: /* HM_HOST */
644 +      arec->Mask.hostname = hostname;
645 +      dlinkAdd(arec, &arec->node, &atable[get_mask_hash(hostname)]);
646 +      break;
647 +  }
648 +
649 +  return arec;
650   }
651  
652 < /* void delete_one_address(const char*, struct AccessItem*)
653 < * Input: An address string, the associated AccessItem.
652 > /* void delete_one_address(const char*, struct MaskItem*)
653 > * Input: An address string, the associated MaskItem.
654   * Output: None
655 < * Side effects: Deletes an address record. Frees the AccessItem if there
655 > * Side effects: Deletes an address record. Frees the MaskItem if there
656   *               is nothing referencing it, sets it as illegal otherwise.
657   */
658   void
659 < delete_one_address_conf(const char *address, struct AccessItem *aconf)
659 > delete_one_address_conf(const char *address, struct MaskItem *conf)
660   {
661 <  int masktype, bits;
662 <  unsigned long hv;
663 <  struct AddressRec *arec, *arecl = NULL;
661 >  int bits = 0;
662 >  uint32_t hv = 0;
663 >  dlink_node *node = NULL;
664    struct irc_ssaddr addr;
699 –  masktype = parse_netmask(address, &addr, &bits);
665  
666 < #ifdef IPV6
702 <  if (masktype == HM_IPV6)
666 >  switch (parse_netmask(address, &addr, &bits))
667    {
668 <    /* We have to do this, since we do not re-hash for every bit -A1kmm. */
669 <    bits -= bits % 16;
670 <    hv = hash_ipv6(&addr, bits);
671 <  }
672 <  else
673 < #endif
674 <  if (masktype == HM_IPV4)
675 <  {
676 <    /* We have to do this, since we do not re-hash for every bit -A1kmm. */
677 <    bits -= bits % 8;
678 <    hv = hash_ipv4(&addr, bits);
668 >    case HM_IPV4:
669 >      /* We have to do this, since we do not re-hash for every bit -A1kmm. */
670 >      bits -= bits % 8;
671 >      hv = hash_ipv4(&addr, bits);
672 >      break;
673 >    case HM_IPV6:
674 >      /* We have to do this, since we do not re-hash for every bit -A1kmm. */
675 >      bits -= bits % 16;
676 >      hv = hash_ipv6(&addr, bits);
677 >      break;
678 >    default: /* HM_HOST */
679 >      hv = get_mask_hash(address);
680 >      break;
681    }
682 <  else
683 <    hv = get_mask_hash(address);
718 <  for (arec = atable[hv]; arec; arec = arec->next)
682 >
683 >  DLINK_FOREACH(node, atable[hv].head)
684    {
685 <    if (arec->aconf == aconf)
685 >    struct AddressRec *arec = node->data;
686 >
687 >    if (arec->conf == conf)
688      {
689 <      if (arecl)
690 <        arecl->next = arec->next;
691 <      else
692 <        atable[hv] = arec->next;
693 <      aconf->status |= CONF_ILLEGAL;
727 <      if (aconf->clients == 0)
728 <        free_access_item(aconf);
689 >      dlinkDelete(&arec->node, &atable[hv]);
690 >
691 >      if (!conf->ref_count)
692 >        conf_free(conf);
693 >
694        MyFree(arec);
695        return;
696      }
732 –    arecl = arec;
697    }
698   }
699  
# Line 737 | Line 701 | delete_one_address_conf(const char *addr
701   * Input: None
702   * Output: None
703   * Side effects: Clears out all address records in the hash table,
704 < *               frees them, and frees the AccessItems if nothing references
705 < *               them, otherwise sets them as illegal.  
704 > *               frees them, and frees the MaskItems if nothing references
705 > *               them, otherwise sets them as illegal.
706   */
707   void
708   clear_out_address_conf(void)
709   {
710 <  int i;
747 <  struct AddressRec *arec;
748 <  struct AddressRec *last_arec;
749 <  struct AddressRec *next_arec;
750 <
751 <  for (i = 0; i < ATABLE_SIZE; i++)
752 <  {
753 <    last_arec = NULL;
754 <    for (arec = atable[i]; arec; arec = next_arec)
755 <    {
756 <      /* We keep the temporary K-lines and destroy the
757 <       * permanent ones, just to be confusing :) -A1kmm
758 <       */  
759 <      next_arec = arec->next;
710 >  dlink_node *node = NULL, *node_next = NULL;
711  
712 <      if (arec->aconf->flags & CONF_FLAGS_TEMPORARY)
713 <      {
714 <        last_arec = arec;
715 <      }
716 <      else  
766 <      {
767 <        /* unlink it from link list - Dianora */
768 <  
769 <        if (last_arec == NULL)
770 <        {
771 <          atable[i] = next_arec;
772 <        }
773 <        else
774 <        {
775 <          last_arec->next = next_arec;
776 <        }
712 >  for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
713 >  {
714 >    DLINK_FOREACH_SAFE(node, node_next, atable[i].head)
715 >    {
716 >      struct AddressRec *arec = node->data;
717  
718 <        arec->aconf->status |= CONF_ILLEGAL;
719 <        if (arec->aconf->clients == 0)
720 <          free_access_item(arec->aconf);
721 <        MyFree(arec);
722 <      }
723 <    }
784 <  }
785 < }
718 >      /*
719 >       * We keep the temporary K-lines and destroy the permanent ones,
720 >       * just to be confusing :) -A1kmm
721 >       */
722 >      if (arec->conf->until || IsConfDatabase(arec->conf))
723 >        continue;
724  
725 < /*
726 < * show_iline_prefix()
789 < *
790 < * inputs       - pointer to struct Client requesting output
791 < *              - pointer to struct AccessItem
792 < *              - name to which iline prefix will be prefixed to
793 < * output       - pointer to static string with prefixes listed in ascii form
794 < * side effects - NONE
795 < */
796 < char *
797 < show_iline_prefix(struct Client *sptr, struct AccessItem *aconf, const char *name)
798 < {
799 <  static char prefix_of_host[USERLEN + 14];
800 <  char *prefix_ptr;
801 <
802 <  prefix_ptr = prefix_of_host;
803 <  if (IsNoTilde(aconf))
804 <    *prefix_ptr++ = '-';
805 <  if (IsLimitIp(aconf))
806 <    *prefix_ptr++ = '!';
807 <  if (IsNeedIdentd(aconf))
808 <    *prefix_ptr++ = '+';
809 <  if (!IsNeedPassword(aconf))
810 <    *prefix_ptr++ = '&';
811 <  if (IsConfExemptResv(aconf))
812 <    *prefix_ptr++ = '$';
813 <  if (IsNoMatchIp(aconf))
814 <    *prefix_ptr++ = '%';
815 <  if (IsConfDoSpoofIp(aconf))
816 <    *prefix_ptr++ = '=';
817 <  if (MyOper(sptr) && IsConfExemptKline(aconf))
818 <    *prefix_ptr++ = '^';
819 <  if (MyOper(sptr) && IsConfExemptGline(aconf))
820 <    *prefix_ptr++ = '_';
821 <  if (MyOper(sptr) && IsConfExemptLimits(aconf))
822 <    *prefix_ptr++ = '>';
823 <  if (MyOper(sptr) && IsConfIdlelined(aconf))
824 <    *prefix_ptr++ = '<';
825 <  if (IsConfCanFlood(aconf))
826 <    *prefix_ptr++ = '|';
827 <  strlcpy(prefix_ptr, name, USERLEN);
725 >      dlinkDelete(&arec->node, &atable[i]);
726 >      arec->conf->active = 0;
727  
728 <  return(prefix_of_host);
728 >      if (!arec->conf->ref_count)
729 >        conf_free(arec->conf);
730 >      MyFree(arec);
731 >    }
732 >  }
733   }
734  
735 < /* report_auth()
736 < *
834 < * Inputs: pointer to client to report to
835 < * Output: None
836 < * Side effects: Reports configured auth{} blocks to client_p
837 < */
838 < void
839 < report_auth(struct Client *client_p)
735 > static void
736 > hostmask_send_expiration(const struct AddressRec *const arec)
737   {
738 <  struct AddressRec *arec;
842 <  struct ConfItem *conf;
843 <  struct AccessItem *aconf;
844 <  int i;
845 <
846 <  for (i = 0; i < ATABLE_SIZE; i++)
847 <  {
848 <    for (arec = atable[i]; arec; arec = arec->next)
849 <    {
850 <      if (arec->type == CONF_CLIENT)
851 <      {
852 <        aconf = arec->aconf;
853 <
854 <        if (!MyOper(client_p) && IsConfDoSpoofIp(aconf))
855 <          continue;
738 >  char ban_type = '\0';
739  
740 <        conf = unmap_conf_item(aconf);
740 >  if (!ConfigGeneral.tkline_expire_notices)
741 >    return;
742  
743 <        /* We are doing a partial list, based on what matches the u@h of the
744 <         * sender, so prepare the strings for comparing --fl_
745 <         */
746 <        if (ConfigFileEntry.hide_spoof_ips)
747 <          sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
748 <                     client_p->name, 'I',
749 <                     conf->name == NULL ? "*" : conf->name,
750 <                     show_iline_prefix(client_p, aconf, aconf->user),
751 <                     IsConfDoSpoofIp(aconf) ? "255.255.255.255" :
752 <                     aconf->host, aconf->port,
753 <                     aconf->class_ptr ? aconf->class_ptr->name : "<default>");
754 <                    
871 <        else
872 <          sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
873 <                     client_p->name, 'I',
874 <                     conf->name == NULL ? "*" : conf->name,
875 <                     show_iline_prefix(client_p, aconf, aconf->user),
876 <                     aconf->host, aconf->port,
877 <                     aconf->class_ptr ? aconf->class_ptr->name : "<default>");
878 <      }
879 <    }
743 >  switch (arec->type)
744 >  {
745 >    case CONF_KLINE:
746 >      ban_type = 'K';
747 >      break;
748 >    case CONF_DLINE:
749 >      ban_type = 'D';
750 >      break;
751 >    case CONF_GLINE:
752 >      ban_type = 'G';
753 >      break;
754 >    default: break;
755    }
756 +
757 +  sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
758 +                       "Temporary %c-line for [%s@%s] expired", ban_type,
759 +                       (arec->conf->user) ? arec->conf->user : "*",
760 +                       (arec->conf->host) ? arec->conf->host : "*");
761   }
762  
883 – /* report_Klines()
884 – * Inputs: Client to report to,
885 – *         type(==0 for perm, !=0 for temporary)
886 – *         mask
887 – * Output: None
888 – * Side effects: Reports configured K(or k)-lines to client_p.
889 – */
763   void
764 < report_Klines(struct Client *client_p, int tkline)
764 > hostmask_expire_temporary(void)
765   {
766 <  struct AddressRec *arec = NULL;
894 <  struct AccessItem *aconf = NULL;
895 <  int i;
896 <  const char *p = NULL;
766 >  dlink_node *node = NULL, *node_next = NULL;
767  
768 <  if (tkline)
899 <    p = "k";
900 <  else
901 <    p = "K";
902 <
903 <  for (i = 0; i < ATABLE_SIZE; i++)
768 >  for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
769    {
770 <    for (arec = atable[i]; arec; arec = arec->next)
770 >    DLINK_FOREACH_SAFE(node, node_next, atable[i].head)
771      {
772 <      if (arec->type == CONF_KILL)
772 >      struct AddressRec *arec = node->data;
773 >
774 >      if (!arec->conf->until || arec->conf->until > CurrentTime)
775 >        continue;
776 >
777 >      switch (arec->type)
778        {
779 <        if ((tkline && !((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)) ||
780 <            (!tkline && ((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)))
781 <          continue;
782 <
783 <        if (IsOper(client_p))
784 <          sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
785 <                     client_p->name, p, aconf->host, aconf->user,
786 <                     aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
787 <        else
788 <          sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
919 <                     client_p->name, p, aconf->host, aconf->user,
920 <                     aconf->reason, "");
779 >        case CONF_KLINE:
780 >        case CONF_DLINE:
781 >        case CONF_GLINE:
782 >          hostmask_send_expiration(arec);
783 >
784 >          dlinkDelete(&arec->node, &atable[i]);
785 >          conf_free(arec->conf);
786 >          MyFree(arec);
787 >          break;
788 >        default: break;
789        }
790      }
791    }

Diff Legend

– Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)