]>
jfr.im git - solanum.git/blob - src/hostmask.c
2 * charybdis: an advanced internet relay chat daemon (ircd).
3 * hostmask.c: Code to efficiently find IP & hostmask based configs.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 * Copyright (C) 2005-2008 charybdis development team
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 * $Id: hostmask.c 2757 2006-11-10 22:58:15Z jilles $
29 #include "ircd_defs.h"
35 #include "ipv4_from_ipv6.h"
38 static unsigned long hash_ipv6(struct sockaddr
*, int);
40 static unsigned long hash_ipv4(struct sockaddr
*, int);
43 /* int parse_netmask(const char *, struct rb_sockaddr_storage *, int *);
44 * Input: A hostmask, or an IPV4/6 address.
45 * Output: An integer describing whether it is an IPV4, IPV6 address or a
46 * hostmask, an address(if it is an IP mask),
47 * a bitlength(if it is IP mask).
51 parse_netmask(const char *text
, struct sockaddr
*naddr
, int *nb
)
53 char *ip
= LOCAL_COPY(text
);
55 struct rb_sockaddr_storage
*addr
, xaddr
;
63 addr
= (struct rb_sockaddr_storage
*)&xaddr
;
65 addr
= (struct rb_sockaddr_storage
*)naddr
;
67 if(strpbrk(ip
, "*?") != NULL
)
74 if((ptr
= strchr(ip
, '/')))
83 if(rb_inet_pton_sock(ip
, (struct sockaddr
*)addr
) > 0)
91 if((ptr
= strchr(ip
, '/')))
100 if(rb_inet_pton_sock(ip
, (struct sockaddr
*)addr
) > 0)
108 /* Hashtable stuff...now external as its used in m_stats.c */
109 struct AddressRec
*atable
[ATABLE_SIZE
];
114 memset(&atable
, 0, sizeof(atable
));
117 /* unsigned long hash_ipv4(struct rb_sockaddr_storage*)
118 * Input: An IP address.
119 * Output: A hash value of the IP address.
123 hash_ipv4(struct sockaddr
*saddr
, int bits
)
125 struct sockaddr_in
*addr
= (struct sockaddr_in
*) saddr
;
129 unsigned long av
= ntohl(addr
->sin_addr
.s_addr
) & ~((1 << (32 - bits
)) - 1);
130 return (av
^ (av
>> 12) ^ (av
>> 24)) & (ATABLE_SIZE
- 1);
136 /* unsigned long hash_ipv6(struct rb_sockaddr_storage*)
137 * Input: An IP address.
138 * Output: A hash value of the IP address.
143 hash_ipv6(struct sockaddr
*saddr
, int bits
)
145 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*) saddr
;
146 unsigned long v
= 0, n
;
147 for (n
= 0; n
< 16; n
++)
151 v
^= addr
->sin6_addr
.s6_addr
[n
];
156 v
^= addr
->sin6_addr
.s6_addr
[n
] & ~((1 << (8 - bits
)) - 1);
157 return v
& (ATABLE_SIZE
- 1);
160 return v
& (ATABLE_SIZE
- 1);
162 return v
& (ATABLE_SIZE
- 1);
166 /* int hash_text(const char *start)
167 * Input: The start of the text to hash.
168 * Output: The hash of the string between 1 and (TH_MAX-1)
169 * Side-effects: None.
172 hash_text(const char *start
)
174 const char *p
= start
;
179 h
= (h
<< 4) - (h
+ (unsigned char) ToLower(*p
++));
182 return (h
& (ATABLE_SIZE
- 1));
185 /* unsigned long get_hash_mask(const char *)
186 * Input: The text to hash.
187 * Output: The hash of the string right of the first '.' past the last
188 * wildcard in the string.
189 * Side-effects: None.
192 get_mask_hash(const char *text
)
194 const char *hp
= "", *p
;
196 for (p
= text
+ strlen(text
) - 1; p
>= text
; p
--)
197 if(*p
== '*' || *p
== '?')
198 return hash_text(hp
);
201 return hash_text(text
);
204 /* struct ConfItem* find_conf_by_address(const char*, struct rb_sockaddr_storage*,
205 * int type, int fam, const char *username)
206 * Input: The hostname, the address, the type of mask to find, the address
207 * family, the username.
208 * Output: The matching value with the highest precedence.
210 * Note: Setting bit 0 of the type means that the username is ignored.
213 find_conf_by_address(const char *name
, const char *sockhost
,
214 const char *orighost
,
215 struct sockaddr
*addr
, int type
, int fam
,
216 const char *username
, const char *auth_user
)
218 unsigned long hprecv
= 0;
219 struct ConfItem
*hprec
= NULL
;
220 struct AddressRec
*arec
;
228 /* Check for IPV6 matches... */
233 for (b
= 128; b
>= 0; b
-= 16)
235 for (arec
= atable
[hash_ipv6(addr
, b
)]; arec
; arec
= arec
->next
)
236 if(arec
->type
== (type
& ~0x1) &&
237 arec
->masktype
== HM_IPV6
&&
238 comp_with_mask_sock(addr
, (struct sockaddr
*)&arec
->Mask
.ipa
.addr
,
239 arec
->Mask
.ipa
.bits
) &&
240 (type
& 0x1 || match(arec
-> username
, username
)) &&
241 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
242 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
243 arec
->precedence
> hprecv
)
245 hprecv
= arec
->precedence
;
254 for (b
= 32; b
>= 0; b
-= 8)
256 for (arec
= atable
[hash_ipv4(addr
, b
)]; arec
; arec
= arec
->next
)
257 if(arec
->type
== (type
& ~0x1) &&
258 arec
->masktype
== HM_IPV4
&&
259 comp_with_mask_sock(addr
, (struct sockaddr
*)&arec
->Mask
.ipa
.addr
,
260 arec
->Mask
.ipa
.bits
) &&
261 (type
& 0x1 || match(arec
->username
, username
)) &&
262 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
263 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
264 arec
->precedence
> hprecv
)
266 hprecv
= arec
->precedence
;
277 for (p
= orighost
; p
!= NULL
;)
279 for (arec
= atable
[hash_text(p
)]; arec
; arec
= arec
->next
)
281 if((arec
->type
== (type
& ~0x1)) &&
282 (arec
->masktype
== HM_HOST
) &&
283 arec
->precedence
> hprecv
&&
284 match(arec
->Mask
.hostname
, orighost
) &&
285 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
286 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
287 (type
& 0x1 || match(arec
->username
, username
)))
289 hprecv
= arec
->precedence
;
298 for (arec
= atable
[0]; arec
; arec
= arec
->next
)
300 if(arec
->type
== (type
& ~0x1) &&
301 arec
->masktype
== HM_HOST
&&
302 arec
->precedence
> hprecv
&&
303 (match(arec
->Mask
.hostname
, orighost
) ||
304 (sockhost
&& match(arec
->Mask
.hostname
, sockhost
))) &&
305 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
306 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
307 (type
& 0x1 || match(arec
->username
, username
)))
309 hprecv
= arec
->precedence
;
318 /* And yes - we have to check p after strchr and p after increment for
320 for (p
= name
; p
!= NULL
;)
322 for (arec
= atable
[hash_text(p
)]; arec
; arec
= arec
->next
)
323 if((arec
->type
== (type
& ~0x1)) &&
324 (arec
->masktype
== HM_HOST
) &&
325 arec
->precedence
> hprecv
&&
326 match(arec
->Mask
.hostname
, name
) &&
327 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
328 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
329 (type
& 0x1 || match(arec
->username
, username
)))
331 hprecv
= arec
->precedence
;
340 for (arec
= atable
[0]; arec
; arec
= arec
->next
)
342 if(arec
->type
== (type
& ~0x1) &&
343 arec
->masktype
== HM_HOST
&&
344 arec
->precedence
> hprecv
&&
345 (match(arec
->Mask
.hostname
, name
) ||
346 (sockhost
&& match(arec
->Mask
.hostname
, sockhost
))) &&
347 (type
!= CONF_CLIENT
|| !arec
->auth_user
||
348 (auth_user
&& match(arec
->auth_user
, auth_user
))) &&
349 (type
& 0x1 || match(arec
->username
, username
)))
351 hprecv
= arec
->precedence
;
359 /* struct ConfItem* find_address_conf(const char*, const char*,
360 * struct rb_sockaddr_storage*, int);
361 * Input: The hostname, username, address, address family.
362 * Output: The applicable ConfItem.
366 find_address_conf(const char *host
, const char *sockhost
, const char *user
,
367 const char *notildeuser
, struct sockaddr
*ip
, int aftype
, char *auth_user
)
369 struct ConfItem
*iconf
, *kconf
;
372 struct sockaddr_in ip4
;
375 /* Find the best I-line... If none, return NULL -A1kmm */
376 if(!(iconf
= find_conf_by_address(host
, sockhost
, NULL
, ip
, CONF_CLIENT
, aftype
, user
, auth_user
)))
378 /* Find what their visible username will be.
379 * Note that the username without tilde may contain one char more.
381 vuser
= IsNoTilde(iconf
) ? notildeuser
: user
;
383 /* If they are exempt from K-lines, return the best I-line. -A1kmm */
384 if(IsConfExemptKline(iconf
))
387 /* Find the best K-line... -A1kmm */
388 kconf
= find_conf_by_address(host
, sockhost
, NULL
, ip
, CONF_KILL
, aftype
, user
, NULL
);
390 /* If they are K-lined, return the K-line */
394 /* if theres a spoof, check it against klines.. */
395 if(IsConfDoSpoofIp(iconf
))
397 char *p
= strchr(iconf
->info
.name
, '@');
399 /* note, we dont need to pass sockhost here, as its
400 * guaranteed to not match by whats above.. --anfl
405 kconf
= find_conf_by_address(p
+1, NULL
, NULL
, ip
, CONF_KILL
, aftype
, iconf
->info
.name
, NULL
);
409 kconf
= find_conf_by_address(iconf
->info
.name
, NULL
, NULL
, ip
, CONF_KILL
, aftype
, vuser
, NULL
);
415 /* if no_tilde, check the username without tilde against klines too
419 kconf
= find_conf_by_address(host
, sockhost
, NULL
, ip
, CONF_KILL
, aftype
, vuser
, NULL
);
425 if(ip
->sa_family
== AF_INET6
&&
426 ipv4_from_ipv6((const struct sockaddr_in6
*)(const void *)ip
, &ip4
))
428 kconf
= find_conf_by_address(NULL
, NULL
, NULL
, (struct sockaddr
*)&ip4
, CONF_KILL
, AF_INET
, vuser
, NULL
);
437 /* struct ConfItem* find_dline(struct rb_sockaddr_storage*, int)
438 * Input: An address, an address family.
439 * Output: The best matching D-line or exempt line.
440 * Side effects: None.
443 find_dline(struct sockaddr
*addr
, int aftype
)
445 struct ConfItem
*aconf
;
447 struct sockaddr_in addr2
;
450 aconf
= find_conf_by_address(NULL
, NULL
, NULL
, addr
, CONF_EXEMPTDLINE
| 1, aftype
, NULL
, NULL
);
453 aconf
= find_conf_by_address(NULL
, NULL
, NULL
, addr
, CONF_DLINE
| 1, aftype
, NULL
, NULL
);
457 if(addr
->sa_family
== AF_INET6
&&
458 ipv4_from_ipv6((const struct sockaddr_in6
*)(const void *)addr
, &addr2
))
460 aconf
= find_conf_by_address(NULL
, NULL
, NULL
, (struct sockaddr
*)&addr2
, CONF_DLINE
| 1, AF_INET
, NULL
, NULL
);
468 /* void find_exact_conf_by_address(const char*, int, const char *)
470 * Output: ConfItem if found
474 find_exact_conf_by_address(const char *address
, int type
, const char *username
)
478 struct AddressRec
*arec
;
479 struct rb_sockaddr_storage addr
;
482 address
= "/NOMATCH!/";
483 masktype
= parse_netmask(address
, (struct sockaddr
*)&addr
, &bits
);
485 if(masktype
== HM_IPV6
)
487 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
488 hv
= hash_ipv6((struct sockaddr
*)&addr
, bits
- bits
% 16);
492 if(masktype
== HM_IPV4
)
494 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
495 hv
= hash_ipv4((struct sockaddr
*)&addr
, bits
- bits
% 8);
499 hv
= get_mask_hash(address
);
501 for (arec
= atable
[hv
]; arec
; arec
= arec
->next
)
503 if (arec
->type
== type
&&
504 arec
->masktype
== masktype
&&
505 (arec
->username
== NULL
|| username
== NULL
? arec
->username
== username
: !irccmp(arec
->username
, username
)))
507 if (masktype
== HM_HOST
)
509 if (!irccmp(arec
->Mask
.hostname
, address
))
514 if (arec
->Mask
.ipa
.bits
== bits
&&
515 comp_with_mask_sock((struct sockaddr
*)&arec
->Mask
.ipa
.addr
, (struct sockaddr
*)&addr
, bits
))
523 /* void add_conf_by_address(const char*, int, const char *,
524 * struct ConfItem *aconf)
527 * Side-effects: Adds this entry to the hash table.
530 add_conf_by_address(const char *address
, int type
, const char *username
, const char *auth_user
, struct ConfItem
*aconf
)
532 static unsigned long prec_value
= 0xFFFFFFFF;
535 struct AddressRec
*arec
;
538 address
= "/NOMATCH!/";
539 arec
= rb_malloc(sizeof(struct AddressRec
));
540 masktype
= parse_netmask(address
, (struct sockaddr
*)&arec
->Mask
.ipa
.addr
, &bits
);
541 arec
->Mask
.ipa
.bits
= bits
;
542 arec
->masktype
= masktype
;
544 if(masktype
== HM_IPV6
)
546 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
548 arec
->next
= atable
[(hv
= hash_ipv6((struct sockaddr
*)&arec
->Mask
.ipa
.addr
, bits
))];
553 if(masktype
== HM_IPV4
)
555 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
557 arec
->next
= atable
[(hv
= hash_ipv4((struct sockaddr
*)&arec
->Mask
.ipa
.addr
, bits
))];
562 arec
->Mask
.hostname
= address
;
563 arec
->next
= atable
[(hv
= get_mask_hash(address
))];
566 arec
->username
= username
;
567 arec
->auth_user
= auth_user
;
569 arec
->precedence
= prec_value
--;
573 /* void delete_one_address(const char*, struct ConfItem*)
574 * Input: An address string, the associated ConfItem.
576 * Side effects: Deletes an address record. Frees the ConfItem if there
577 * is nothing referencing it, sets it as illegal otherwise.
580 delete_one_address_conf(const char *address
, struct ConfItem
*aconf
)
584 struct AddressRec
*arec
, *arecl
= NULL
;
585 struct rb_sockaddr_storage addr
;
586 masktype
= parse_netmask(address
, (struct sockaddr
*)&addr
, &bits
);
588 if(masktype
== HM_IPV6
)
590 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
592 hv
= hash_ipv6((struct sockaddr
*)&addr
, bits
);
596 if(masktype
== HM_IPV4
)
598 /* We have to do this, since we do not re-hash for every bit -A1kmm. */
600 hv
= hash_ipv4((struct sockaddr
*)&addr
, bits
);
603 hv
= get_mask_hash(address
);
604 for (arec
= atable
[hv
]; arec
; arec
= arec
->next
)
606 if(arec
->aconf
== aconf
)
609 arecl
->next
= arec
->next
;
611 atable
[hv
] = arec
->next
;
612 aconf
->status
|= CONF_ILLEGAL
;
622 /* void clear_out_address_conf(void)
625 * Side effects: Clears out all address records in the hash table,
626 * frees them, and frees the ConfItems if nothing references
627 * them, otherwise sets them as illegal.
630 clear_out_address_conf(void)
633 struct AddressRec
**store_next
;
634 struct AddressRec
*arec
, *arecn
;
636 for (i
= 0; i
< ATABLE_SIZE
; i
++)
638 store_next
= &atable
[i
];
639 for (arec
= atable
[i
]; arec
; arec
= arecn
)
642 /* We keep the temporary K-lines and destroy the
643 * permanent ones, just to be confusing :) -A1kmm */
644 if(arec
->aconf
->flags
& CONF_FLAGS_TEMPORARY
||
645 (arec
->type
!= CONF_CLIENT
&& arec
->type
!= CONF_EXEMPTDLINE
))
648 store_next
= &arec
->next
;
652 arec
->aconf
->status
|= CONF_ILLEGAL
;
653 if(!arec
->aconf
->clients
)
654 free_conf(arec
->aconf
);
663 clear_out_address_conf_bans(void)
666 struct AddressRec
**store_next
;
667 struct AddressRec
*arec
, *arecn
;
669 for (i
= 0; i
< ATABLE_SIZE
; i
++)
671 store_next
= &atable
[i
];
672 for (arec
= atable
[i
]; arec
; arec
= arecn
)
675 /* We keep the temporary K-lines and destroy the
676 * permanent ones, just to be confusing :) -A1kmm */
677 if(arec
->aconf
->flags
& CONF_FLAGS_TEMPORARY
||
678 (arec
->type
== CONF_CLIENT
|| arec
->type
== CONF_EXEMPTDLINE
))
681 store_next
= &arec
->next
;
685 arec
->aconf
->status
|= CONF_ILLEGAL
;
686 if(!arec
->aconf
->clients
)
687 free_conf(arec
->aconf
);
697 * show_iline_prefix()
699 * inputs - pointer to struct Client requesting output
700 * - pointer to struct ConfItem
701 * - name to which iline prefix will be prefixed to
702 * output - pointer to static string with prefixes listed in ascii form
703 * side effects - NONE
706 show_iline_prefix(struct Client
*sptr
, struct ConfItem
*aconf
, char *name
)
708 static char prefix_of_host
[USERLEN
+ 15];
711 prefix_ptr
= prefix_of_host
;
714 if(IsNeedIdentd(aconf
))
716 if(IsConfDoSpoofIp(aconf
))
718 if(IsOper(sptr
) && IsConfExemptFlood(aconf
))
720 if(IsOper(sptr
) && IsConfExemptDNSBL(aconf
) && !IsConfExemptKline(aconf
))
722 if(IsOper(sptr
) && IsConfExemptKline(aconf
))
724 if(IsOper(sptr
) && IsConfExemptLimits(aconf
))
727 strncpy(prefix_ptr
, name
, USERLEN
);
728 return (prefix_of_host
);
733 * Inputs: pointer to client to report to
735 * Side effects: Reports configured auth{} blocks to client_p
738 report_auth(struct Client
*client_p
)
740 char *name
, *host
, *pass
, *user
, *classname
;
741 struct AddressRec
*arec
;
742 struct ConfItem
*aconf
;
745 for (i
= 0; i
< ATABLE_SIZE
; i
++)
746 for (arec
= atable
[i
]; arec
; arec
= arec
->next
)
747 if(arec
->type
== CONF_CLIENT
)
751 if(!IsOper(client_p
) && IsConfDoSpoofIp(aconf
))
754 get_printable_conf(aconf
, &name
, &host
, &pass
, &user
, &port
,
757 if(!EmptyString(aconf
->spasswd
))
758 pass
= aconf
->spasswd
;
760 sendto_one_numeric(client_p
, RPL_STATSILINE
,
761 form_str(RPL_STATSILINE
),
762 name
, pass
, show_iline_prefix(client_p
, aconf
, user
),
763 show_ip_conf(aconf
, client_p
) ? host
: "255.255.255.255",
770 * inputs - Client to report to, mask
772 * side effects - Reports configured K-lines to client_p.
775 report_Klines(struct Client
*source_p
)
777 char *host
, *pass
, *user
, *oper_reason
;
778 struct AddressRec
*arec
;
779 struct ConfItem
*aconf
= NULL
;
782 for (i
= 0; i
< ATABLE_SIZE
; i
++)
784 for (arec
= atable
[i
]; arec
; arec
= arec
->next
)
786 if(arec
->type
== CONF_KILL
)
790 /* its a tempkline, theyre reported elsewhere */
791 if(aconf
->flags
& CONF_FLAGS_TEMPORARY
)
794 get_printable_kline(source_p
, aconf
, &host
, &pass
, &user
, &oper_reason
);
795 sendto_one_numeric(source_p
, RPL_STATSKLINE
,
796 form_str(RPL_STATSKLINE
),
797 'K', host
, user
, pass
,
798 oper_reason
? "|" : "",
799 oper_reason
? oper_reason
: "");