31 |
#include "hostmask.h" |
#include "hostmask.h" |
32 |
#include "irc_string.h" |
#include "irc_string.h" |
33 |
#include "memory.h" |
#include "memory.h" |
34 |
|
#include "patricia.h" |
35 |
|
|
36 |
|
|
37 |
struct ClassItem *class_default; |
struct ClassItem *class_default; |
56 |
class->max_total = MAXIMUM_LINKS_DEFAULT; |
class->max_total = MAXIMUM_LINKS_DEFAULT; |
57 |
class->max_sendq = DEFAULT_SENDQ; |
class->max_sendq = DEFAULT_SENDQ; |
58 |
class->max_recvq = DEFAULT_RECVQ; |
class->max_recvq = DEFAULT_RECVQ; |
59 |
|
class->ip_tree = patricia_new(PATRICIA_MAXBITS); |
60 |
|
|
61 |
dlinkAdd(class, &class->node, &class_list); |
dlinkAdd(class, &class->node, &class_list); |
62 |
|
|
70 |
assert(class->active == 0); |
assert(class->active == 0); |
71 |
assert(class->ref_count == 0); |
assert(class->ref_count == 0); |
72 |
|
|
73 |
|
if (class->ip_tree) |
74 |
|
patricia_destroy(class->ip_tree, NULL); |
75 |
|
|
76 |
dlinkDelete(&class->node, &class_list); |
dlinkDelete(&class->node, &class_list); |
77 |
xfree(class->name); |
xfree(class->name); |
78 |
xfree(class); |
xfree(class); |
171 |
struct ClassItem *class = node->data; |
struct ClassItem *class = node->data; |
172 |
|
|
173 |
if (class->active == 0 && class->ref_count == 0) |
if (class->active == 0 && class->ref_count == 0) |
|
{ |
|
|
destroy_cidr_class(class); |
|
174 |
class_free(class); |
class_free(class); |
|
} |
|
175 |
} |
} |
176 |
} |
} |
177 |
|
|
|
/* |
|
|
* cidr_limit_reached |
|
|
* |
|
|
* inputs - int flag allowing over_rule of limits |
|
|
* - pointer to the ip to be added |
|
|
* - pointer to the class |
|
|
* output - non zero if limit reached |
|
|
* 0 if limit not reached |
|
|
* side effects - |
|
|
*/ |
|
178 |
int |
int |
179 |
cidr_limit_reached(int over_rule, struct irc_ssaddr *ip, struct ClassItem *class) |
class_ip_limit_add(struct ClassItem *class, struct sockaddr *addr, int over_rule) |
180 |
{ |
{ |
181 |
dlink_node *node; |
int bitlen; |
182 |
|
|
183 |
if (class->number_per_cidr == 0) |
if (addr->sa_family == AF_INET6) |
184 |
return 0; |
bitlen = class->cidr_bitlen_ipv6; |
185 |
|
else |
186 |
|
bitlen = class->cidr_bitlen_ipv4; |
187 |
|
|
188 |
if (ip->ss.ss_family == AF_INET) |
if (class->number_per_cidr == 0 || bitlen == 0) |
189 |
{ |
return 0; |
|
if (class->cidr_bitlen_ipv4 == 0) |
|
|
return 0; |
|
190 |
|
|
191 |
DLINK_FOREACH(node, class->list_ipv4.head) |
patricia_node_t *pnode = patricia_make_and_lookup_addr(class->ip_tree, addr, bitlen); |
192 |
{ |
if (((uintptr_t)pnode->data) >= class->number_per_cidr && over_rule == 0) |
193 |
struct CidrItem *cidr = node->data; |
return 1; |
|
|
|
|
if (match_ipv4(ip, &cidr->mask, class->cidr_bitlen_ipv4)) |
|
|
{ |
|
|
if (!over_rule && (cidr->number_on_this_cidr >= class->number_per_cidr)) |
|
|
return -1; |
|
|
|
|
|
cidr->number_on_this_cidr++; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
struct CidrItem *cidr = xcalloc(sizeof(*cidr)); |
|
|
cidr->number_on_this_cidr = 1; |
|
|
cidr->mask = *ip; |
|
|
mask_addr(&cidr->mask, class->cidr_bitlen_ipv4); |
|
|
dlinkAdd(cidr, &cidr->node, &class->list_ipv4); |
|
|
} |
|
|
else if (class->cidr_bitlen_ipv6 > 0) |
|
|
{ |
|
|
DLINK_FOREACH(node, class->list_ipv6.head) |
|
|
{ |
|
|
struct CidrItem *cidr = node->data; |
|
|
|
|
|
if (match_ipv6(ip, &cidr->mask, class->cidr_bitlen_ipv6)) |
|
|
{ |
|
|
if (!over_rule && (cidr->number_on_this_cidr >= class->number_per_cidr)) |
|
|
return -1; |
|
|
|
|
|
cidr->number_on_this_cidr++; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
struct CidrItem *cidr = xcalloc(sizeof(*cidr)); |
|
|
cidr->number_on_this_cidr = 1; |
|
|
cidr->mask = *ip; |
|
|
mask_addr(&cidr->mask, class->cidr_bitlen_ipv6); |
|
|
dlinkAdd(cidr, &cidr->node, &class->list_ipv6); |
|
|
} |
|
194 |
|
|
195 |
|
PATRICIA_DATA_SET(pnode, (((uintptr_t)pnode->data) + 1)); |
196 |
return 0; |
return 0; |
197 |
} |
} |
198 |
|
|
199 |
/* |
int |
200 |
* remove_from_cidr_check |
class_ip_limit_remove(struct ClassItem *class, struct sockaddr *addr) |
|
* |
|
|
* inputs - pointer to the ip to be removed |
|
|
* - pointer to the class |
|
|
* output - NONE |
|
|
* side effects - |
|
|
*/ |
|
|
void |
|
|
remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass) |
|
201 |
{ |
{ |
202 |
dlink_node *node, *node_next; |
int bitlen; |
203 |
|
|
204 |
if (aclass->number_per_cidr == 0) |
if (addr->sa_family == AF_INET6) |
205 |
return; |
bitlen = class->cidr_bitlen_ipv6; |
206 |
|
else |
207 |
|
bitlen = class->cidr_bitlen_ipv4; |
208 |
|
|
209 |
if (ip->ss.ss_family == AF_INET) |
if (class->number_per_cidr == 0 || bitlen == 0) |
210 |
{ |
return 0; |
|
if (aclass->cidr_bitlen_ipv4 == 0) |
|
|
return; |
|
211 |
|
|
212 |
DLINK_FOREACH_SAFE(node, node_next, aclass->list_ipv4.head) |
patricia_node_t *pnode = patricia_try_search_best_addr(class->ip_tree, addr, 0); |
213 |
{ |
if (pnode == NULL) |
214 |
struct CidrItem *cidr = node->data; |
return 0; |
215 |
|
|
216 |
if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4)) |
PATRICIA_DATA_SET(pnode, (((uintptr_t)pnode->data) - 1)); |
217 |
{ |
|
218 |
cidr->number_on_this_cidr--; |
if (((uintptr_t)pnode->data) == 0) |
|
|
|
|
if (cidr->number_on_this_cidr == 0) |
|
|
{ |
|
|
dlinkDelete(node, &aclass->list_ipv4); |
|
|
xfree(cidr); |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (aclass->cidr_bitlen_ipv6 > 0) |
|
219 |
{ |
{ |
220 |
DLINK_FOREACH_SAFE(node, node_next, aclass->list_ipv6.head) |
patricia_remove(class->ip_tree, pnode); |
221 |
{ |
return 1; |
|
struct CidrItem *cidr = node->data; |
|
|
|
|
|
if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6)) |
|
|
{ |
|
|
cidr->number_on_this_cidr--; |
|
|
|
|
|
if (cidr->number_on_this_cidr == 0) |
|
|
{ |
|
|
dlinkDelete(node, &aclass->list_ipv6); |
|
|
xfree(cidr); |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
222 |
} |
} |
223 |
|
|
224 |
|
return 0; |
225 |
} |
} |
226 |
|
|
227 |
void |
void |
228 |
rebuild_cidr_list(struct ClassItem *class) |
class_ip_limit_rebuild(struct ClassItem *class) |
229 |
{ |
{ |
230 |
dlink_node *node; |
dlink_node *node; |
231 |
|
|
232 |
destroy_cidr_class(class); |
patricia_clear(class->ip_tree, NULL); |
233 |
|
|
234 |
DLINK_FOREACH(node, local_client_list.head) |
DLINK_FOREACH(node, local_client_list.head) |
235 |
{ |
{ |
236 |
struct Client *client_p = node->data; |
struct Client *client_p = node->data; |
237 |
struct MaskItem *conf = client_p->connection->confs.tail->data; |
struct MaskItem *conf = client_p->connection->confs.tail->data; |
238 |
|
|
239 |
if (conf && (conf->type == CONF_CLIENT)) |
if (conf->type == CONF_CLIENT) |
240 |
if (conf->class == class) |
if (conf->class == class) |
241 |
cidr_limit_reached(1, &client_p->ip, class); |
class_ip_limit_add(class, (struct sockaddr *)&client_p->ip, 1); |
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* destroy_cidr_list |
|
|
* |
|
|
* inputs - pointer to class dlink list of cidr blocks |
|
|
* output - none |
|
|
* side effects - completely destroys the class link list of cidr blocks |
|
|
*/ |
|
|
static void |
|
|
destroy_cidr_list(dlink_list *list) |
|
|
{ |
|
|
while (list->head) |
|
|
{ |
|
|
struct CidrItem *cidr = list->head->data; |
|
|
dlinkDelete(&cidr->node, list); |
|
|
xfree(cidr); |
|
242 |
} |
} |
243 |
} |
} |
|
|
|
|
/* |
|
|
* destroy_cidr_class |
|
|
* |
|
|
* inputs - pointer to class |
|
|
* output - none |
|
|
* side effects - completely destroys the class link list of cidr blocks |
|
|
*/ |
|
|
void |
|
|
destroy_cidr_class(struct ClassItem *class) |
|
|
{ |
|
|
destroy_cidr_list(&class->list_ipv4); |
|
|
destroy_cidr_list(&class->list_ipv6); |
|
|
} |
|