[mod_limit] Fix liSocketAddress usage in combination with radix trees

personal/stbuehler/wip
Thomas Porzelt 12 years ago
parent c972bea1e0
commit 7e94308ea6
  1. 66
      src/modules/mod_limit.c

@ -152,13 +152,25 @@ static void mod_limit_context_free(liServer *srv, mod_limit_context *ctx) {
static void mod_limit_timeout_callback(liWaitQueue *wq, gpointer data) {
liWaitQueueElem *wqe;
mod_limit_req_ip_data *rid;
gpointer addr;
guint32 bits;
UNUSED(data);
while ((wqe = li_waitqueue_pop(wq)) != NULL) {
rid = wqe->data;
/* IPv4 or IPv6? */
if (rid->ip.addr->plain.sa_family == AF_INET) {
addr = &rid->ip.addr->ipv4.sin_addr.s_addr;
bits = 32;
} else {
addr = &rid->ip.addr->ipv6.sin6_addr.s6_addr;
bits = 128;
}
g_mutex_lock(rid->ctx->mutex);
li_radixtree_remove(rid->ctx->pool.req_ip, rid->ip.addr, rid->ip.len * 8);
li_radixtree_remove(rid->ctx->pool.req_ip, addr, bits);
g_mutex_unlock(rid->ctx->mutex);
li_sockaddr_clear(&rid->ip);
g_slice_free(mod_limit_req_ip_data, rid);
@ -172,7 +184,9 @@ static void mod_limit_vrclose(liVRequest *vr, liPlugin *p) {
mod_limit_context *ctx;
guint i;
gint cons;
liSocketAddress remote_addr = vr->coninfo->remote_addr;
liSocketAddress *remote_addr = &vr->coninfo->remote_addr;
gpointer addr;
guint32 bits;
if (!arr)
return;
@ -185,13 +199,22 @@ static void mod_limit_vrclose(liVRequest *vr, liPlugin *p) {
g_atomic_int_add(&ctx->pool.con, -1);
break;
case ML_TYPE_CON_IP:
/* IPv4 or IPv6? */
if (remote_addr->addr->plain.sa_family == AF_INET) {
addr = &remote_addr->addr->ipv4.sin_addr.s_addr;
bits = 32;
} else {
addr = &remote_addr->addr->ipv6.sin6_addr.s6_addr;
bits = 128;
}
g_mutex_lock(ctx->mutex);
cons = GPOINTER_TO_INT(li_radixtree_lookup_exact(ctx->pool.con_ip, remote_addr.addr, remote_addr.len * 8));
cons = GPOINTER_TO_INT(li_radixtree_lookup_exact(ctx->pool.con_ip, addr, bits));
cons--;
if (!cons) {
li_radixtree_remove(ctx->pool.con_ip, remote_addr.addr, remote_addr.len * 8);
li_radixtree_remove(ctx->pool.con_ip, addr, bits);
} else {
li_radixtree_insert(ctx->pool.con_ip, remote_addr.addr, remote_addr.len * 8, GINT_TO_POINTER(cons));
li_radixtree_insert(ctx->pool.con_ip, addr, bits, GINT_TO_POINTER(cons));
}
g_mutex_unlock(ctx->mutex);
break;
@ -213,7 +236,9 @@ static liHandlerResult mod_limit_action_handle(liVRequest *vr, gpointer param, g
GPtrArray *arr = g_ptr_array_index(vr->plugin_ctx, ctx->plugin->id);
gint cons;
mod_limit_req_ip_data *rid;
liSocketAddress remote_addr = vr->coninfo->remote_addr;
liSocketAddress *remote_addr = &vr->coninfo->remote_addr;
gpointer addr;
guint32 bits;
UNUSED(context);
@ -222,6 +247,25 @@ static liHandlerResult mod_limit_action_handle(liVRequest *vr, gpointer param, g
return LI_HANDLER_GO_ON;
}
/* IPv4 or IPv6? */
switch (remote_addr->addr->plain.sa_family) {
case AF_INET:
addr = &remote_addr->addr->ipv4.sin_addr.s_addr;
bits = 32;
break;
case AF_INET6:
addr = &remote_addr->addr->ipv6.sin6_addr.s6_addr;
bits = 128;
break;
default:
if (ctx->type == ML_TYPE_CON_IP || ctx->type == ML_TYPE_REQ_IP) {
VR_DEBUG(vr, "%s", "mod_limit only supports ipv4 or ipv6 clients");
return LI_HANDLER_ERROR;
}
addr = NULL;
bits = 0;
}
if (!arr) {
/* request is not in any context yet, create new array */
arr = g_ptr_array_sized_new(2);
@ -238,9 +282,9 @@ static liHandlerResult mod_limit_action_handle(liVRequest *vr, gpointer param, g
break;
case ML_TYPE_CON_IP:
g_mutex_lock(ctx->mutex);
cons = GPOINTER_TO_INT(li_radixtree_lookup_exact(ctx->pool.con_ip, remote_addr.addr, remote_addr.len * 8));
cons = GPOINTER_TO_INT(li_radixtree_lookup_exact(ctx->pool.con_ip, addr, bits));
if (cons < ctx->limit) {
li_radixtree_insert(ctx->pool.con_ip, remote_addr.addr, remote_addr.len * 8, GINT_TO_POINTER(cons+1));
li_radixtree_insert(ctx->pool.con_ip, addr, bits, GINT_TO_POINTER(cons+1));
} else {
limit_reached = TRUE;
VR_DEBUG(vr, "limit.con_ip: limit reached (%d active connections)", ctx->limit);
@ -264,15 +308,15 @@ static liHandlerResult mod_limit_action_handle(liVRequest *vr, gpointer param, g
break;
case ML_TYPE_REQ_IP:
g_mutex_lock(ctx->mutex);
rid = li_radixtree_lookup_exact(ctx->pool.req_ip, remote_addr.addr, remote_addr.len * 8);
rid = li_radixtree_lookup_exact(ctx->pool.req_ip, addr, bits);
if (!rid) {
/* IP not known */
rid = g_slice_new0(mod_limit_req_ip_data);
rid->requests = 1;
rid->ip = li_sockaddr_dup(remote_addr);
rid->ip = li_sockaddr_dup(*remote_addr);
rid->ctx = ctx;
rid->timeout_elem.data = rid;
li_radixtree_insert(ctx->pool.req_ip, remote_addr.addr, remote_addr.len * 8, rid);
li_radixtree_insert(ctx->pool.req_ip, addr, bits, rid);
li_waitqueue_push(&(((mod_limit_data*)ctx->plugin->data)->timeout_queues[vr->wrk->ndx]), &rid->timeout_elem);
} else if (rid->requests < ctx->limit) {
rid->requests++;

Loading…
Cancel
Save