diff --git a/src/modules/mod_limit.c b/src/modules/mod_limit.c index 82ce419..3519c3b 100644 --- a/src/modules/mod_limit.c +++ b/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++;