From: Alan T. DeKok Date: Sun, 29 Apr 2012 16:59:25 +0000 (+0200) Subject: Rate limit some triggers. X-Git-Tag: release_3_0_0_beta0~210 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69eb955b17a55627fdeb397bd14b10ee2fa4a426;p=thirdparty%2Ffreeradius-server.git Rate limit some triggers. e.g. LDAP query timeout --- diff --git a/src/include/radiusd.h b/src/include/radiusd.h index bf2b0898f4a..69f9bd6c8fc 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -682,7 +682,7 @@ int radius_exec_program(const char *, REQUEST *, int, VALUE_PAIR *input_pairs, VALUE_PAIR **output_pairs, int shell_escape); -void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name); +void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name, int quench); /* timestr.c */ int timestr_match(char *, time_t); diff --git a/src/main/command.c b/src/main/command.c index e45fe20fa57..34c7b03b3f9 100644 --- a/src/main/command.c +++ b/src/main/command.c @@ -326,7 +326,7 @@ static int command_hup(rad_listen_t *listener, int argc, char *argv[]) snprintf(buffer, sizeof(buffer), "modules.%s.hup", cf_section_name1(mi->cs)); - exec_trigger(NULL, mi->cs, buffer); + exec_trigger(NULL, mi->cs, buffer, TRUE); return 1; /* success */ } diff --git a/src/main/connection.c b/src/main/connection.c index d28343fc2e1..01382b562f2 100644 --- a/src/main/connection.c +++ b/src/main/connection.c @@ -221,7 +221,7 @@ static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *fc, pthread_mutex_unlock(&fc->mutex); - if (fc->trigger) exec_trigger(NULL, fc->cs, "open"); + if (fc->trigger) exec_trigger(NULL, fc->cs, "open", TRUE); return this; } @@ -264,7 +264,7 @@ int fr_connection_add(fr_connection_pool_t *fc, void *conn) pthread_mutex_unlock(&fc->mutex); - if (fc->trigger) exec_trigger(NULL, fc->cs, "open"); + if (fc->trigger) exec_trigger(NULL, fc->cs, "open", TRUE); return 1; } @@ -273,7 +273,7 @@ int fr_connection_add(fr_connection_pool_t *fc, void *conn) static void fr_connection_close(fr_connection_pool_t *fc, fr_connection_t *this) { - if (fc->trigger) exec_trigger(NULL, fc->cs, "close"); + if (fc->trigger) exec_trigger(NULL, fc->cs, "close", TRUE); rad_assert(this->used == FALSE); @@ -343,7 +343,7 @@ void fr_connection_pool_delete(fr_connection_pool_t *fc) fr_connection_close(fc, this); } - if (fc->trigger) exec_trigger(NULL, fc->cs, "stop"); + if (fc->trigger) exec_trigger(NULL, fc->cs, "stop", TRUE); rad_assert(fc->head == NULL); rad_assert(fc->tail == NULL); @@ -446,7 +446,7 @@ fr_connection_pool_t *fr_connection_pool_init(CONF_SECTION *parent, } } - if (fc->trigger) exec_trigger(NULL, fc->cs, "start"); + if (fc->trigger) exec_trigger(NULL, fc->cs, "start", TRUE); return fc; } diff --git a/src/main/exec.c b/src/main/exec.c index 22f0cf31eab..16155d87693 100644 --- a/src/main/exec.c +++ b/src/main/exec.c @@ -741,7 +741,12 @@ int radius_exec_program(const char *cmd, REQUEST *request, return 1; } -void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name) +static void time_free(void *data) +{ + free(data); +} + +void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name, int quench) { CONF_SECTION *subcs; CONF_ITEM *ci; @@ -810,6 +815,34 @@ void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name) vp = NULL; if (request && request->packet) vp = request->packet->vps; + /* + * Perform periodic quenching. + */ + if (quench) { + time_t *last_time; + + last_time = cf_data_find(cs, value); + if (!last_time) { + last_time = rad_malloc(sizeof(*last_time)); + *last_time = 0; + + if (cf_data_add(cs, value, last_time, time_free) < 0) { + free(last_time); + last_time = NULL; + } + } + + /* + * Send the quenched traps at most once per second. + */ + if (last_time) { + time_t now = time(NULL); + if (*last_time == now) return; + + *last_time = now; + } + } + DEBUG("Trigger %s -> %s", name, value); radius_exec_program(value, request, 0, NULL, 0, vp, NULL, 1); } diff --git a/src/main/listen.c b/src/main/listen.c index 4bbf940a7f8..fd9d902e929 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -300,7 +300,7 @@ RADCLIENT *client_listener_find(rad_listen_t *listener, } request->server = client->server; - exec_trigger(request, NULL, "server.client.add"); + exec_trigger(request, NULL, "server.client.add", FALSE); request_free(&request); diff --git a/src/main/process.c b/src/main/process.c index 710534d8097..353d4587cbe 100644 --- a/src/main/process.c +++ b/src/main/process.c @@ -646,7 +646,7 @@ static void request_process_timer(REQUEST *request) request->number, request->component ? request->component : "", request->module ? request->module : ""); - exec_trigger(request, NULL, "server.thread.unresponsive"); + exec_trigger(request, NULL, "server.thread.unresponsive", TRUE); } #endif @@ -1280,22 +1280,13 @@ int request_receive(rad_listen_t *listener, RADIUS_PACKET *packet, */ if (mainconfig.max_requests && ((count = fr_packet_list_num_elements(pl)) > mainconfig.max_requests)) { - static time_t last_complained = 0; - radlog(L_ERR, "Dropping request (%d is too many): from client %s port %d - ID: %d", count, client->shortname, packet->src_port, packet->id); radlog(L_INFO, "WARNING: Please check the configuration file.\n" "\tThe value for 'max_requests' is probably set too low.\n"); - /* - * Complain once every 10 seconds. - */ - if ((last_complained + 10) < now.tv_sec) { - last_complained = now.tv_sec; - exec_trigger(NULL, NULL, "server.max_requests"); - } - + exec_trigger(NULL, NULL, "server.max_requests", TRUE); return 0; } @@ -2454,7 +2445,7 @@ STATE_MACHINE_DECL(request_ping) * pings. */ home->state = HOME_STATE_ALIVE; - exec_trigger(request, request->home_server->cs, "home_server.alive"); + exec_trigger(request, request->home_server->cs, "home_server.alive", FALSE); home->currently_outstanding = 0; home->num_sent_pings = 0; home->num_received_pings = 0; @@ -2633,7 +2624,7 @@ static void home_trigger(home_server *home, const char *trigger) my_packet.dst_ipaddr = home->ipaddr; my_packet.src_ipaddr = home->src_ipaddr; - exec_trigger(&my_request, home->cs, trigger); + exec_trigger(&my_request, home->cs, trigger, FALSE); } static void mark_home_server_zombie(home_server *home) @@ -3792,7 +3783,7 @@ static void handle_signal_self(int flag) fr_event_loop_exit(el, 1); } else { radlog(L_INFO, "Signalled to terminate"); - exec_trigger(NULL, NULL, "server.signal.term"); + exec_trigger(NULL, NULL, "server.signal.term", TRUE); fr_event_loop_exit(el, 2); } @@ -3816,7 +3807,7 @@ static void handle_signal_self(int flag) last_hup = when; - exec_trigger(NULL, NULL, "server.signal.hup"); + exec_trigger(NULL, NULL, "server.signal.hup", TRUE); fr_event_loop_exit(el, 0x80); } diff --git a/src/main/radiusd.c b/src/main/radiusd.c index e9cf50fcf04..6e4dee36c1f 100644 --- a/src/main/radiusd.c +++ b/src/main/radiusd.c @@ -405,7 +405,7 @@ int main(int argc, char *argv[]) } } - exec_trigger(NULL, NULL, "server.start"); + exec_trigger(NULL, NULL, "server.start", FALSE); /* * Process requests until HUP or exit. @@ -425,7 +425,7 @@ int main(int argc, char *argv[]) radlog(L_INFO, "Exiting normally."); } - exec_trigger(NULL, NULL, "server.stop"); + exec_trigger(NULL, NULL, "server.stop", FALSE); /* * Ignore the TERM signal: we're diff --git a/src/main/realms.c b/src/main/realms.c index 8f2966cab6e..eb73acdc4bf 100644 --- a/src/main/realms.c +++ b/src/main/realms.c @@ -2294,7 +2294,7 @@ home_server *home_server_ldb(const char *realmname, */ if ((pool->time_all_dead + 3600) < request->timestamp) { pool->time_all_dead = request->timestamp; - exec_trigger(request, pool->cs, "home_server_pool.fallback"); + exec_trigger(request, pool->cs, "home_server_pool.fallback", FALSE); } } @@ -2302,7 +2302,7 @@ home_server *home_server_ldb(const char *realmname, update_and_return: if ((found != pool->fallback) && pool->in_fallback) { pool->in_fallback = FALSE; - exec_trigger(request, pool->cs, "home_server_pool.normal"); + exec_trigger(request, pool->cs, "home_server_pool.normal", FALSE); } /* diff --git a/src/main/threads.c b/src/main/threads.c index 9bc68d5038d..51e74fd1460 100644 --- a/src/main/threads.c +++ b/src/main/threads.c @@ -654,7 +654,7 @@ static void *request_handler_thread(void *arg) */ self->request = NULL; self->status = THREAD_EXITED; - exec_trigger(NULL, NULL, "server.thread.stop"); + exec_trigger(NULL, NULL, "server.thread.stop", TRUE); return NULL; } @@ -721,7 +721,7 @@ static THREAD_HANDLE *spawn_thread(time_t now, int do_trigger) */ if (thread_pool.total_threads >= thread_pool.max_threads) { DEBUG2("Thread spawn failed. Maximum number of threads (%d) already running.", thread_pool.max_threads); - exec_trigger(NULL, NULL, "server.thread.max_threads"); + exec_trigger(NULL, NULL, "server.thread.max_threads", TRUE); return NULL; } @@ -769,7 +769,7 @@ static THREAD_HANDLE *spawn_thread(time_t now, int do_trigger) thread_pool.total_threads++; DEBUG2("Thread spawned new child %d. Total threads in pool: %d", handle->thread_num, thread_pool.total_threads); - if (do_trigger) exec_trigger(NULL, NULL, "server.thread.start"); + if (do_trigger) exec_trigger(NULL, NULL, "server.thread.start", TRUE); /* * Add the thread handle to the tail of the thread pool list. diff --git a/src/main/xlat.c b/src/main/xlat.c index e6941ca253c..522bcf27ae1 100644 --- a/src/main/xlat.c +++ b/src/main/xlat.c @@ -110,14 +110,14 @@ static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, return strlen(out); } -static VALUE_PAIR *pairfind_tag(VALUE_PAIR *vps, int attr, int tag) +static VALUE_PAIR *pairfind_tag(VALUE_PAIR *vps, const DICT_ATTR *da, int tag) { VALUE_PAIR *vp = vps; redo: if (!vp) return NULL; - vp = pairfind(vp, attr); + vp = pairfind(vp, da->attr, da->vendor); if (!tag) return vp; if (!vp->flags.has_tag) return NULL; @@ -271,7 +271,7 @@ static size_t xlat_packet(void *instance, REQUEST *request, * No array, print the tagged attribute. */ if (!do_array) { - vp = pairfind_tag(vps, da->attr, tag); + vp = pairfind_tag(vps, da, tag); goto just_print; } @@ -281,9 +281,9 @@ static size_t xlat_packet(void *instance, REQUEST *request, * Array[#] - return the total */ if (do_count) { - for (vp = pairfind_tag(vps, da->attr, tag); + for (vp = pairfind_tag(vps, da, tag); vp != NULL; - vp = pairfind_tag(vp->next, da->attr, tag)) { + vp = pairfind_tag(vp->next, da, tag)) { total++; } @@ -296,9 +296,9 @@ static size_t xlat_packet(void *instance, REQUEST *request, * the attributes, separated by a newline. */ if (do_all) { - for (vp = pairfind_tag(vps, da->attr, tag); + for (vp = pairfind_tag(vps, da, tag); vp != NULL; - vp = pairfind_tag(vp->next, da->attr, tag)) { + vp = pairfind_tag(vp->next, da, tag)) { count = valuepair2str(out, outlen - 1, vp, da->type, func); rad_assert(count <= outlen); total += count + 1; @@ -317,9 +317,9 @@ static size_t xlat_packet(void *instance, REQUEST *request, /* * Find the N'th value. */ - for (vp = pairfind_tag(vps, da->attr, tag); + for (vp = pairfind_tag(vps, da, tag); vp != NULL; - vp = pairfind_tag(vp->next, da->attr, tag)) { + vp = pairfind_tag(vp->next, da, tag)) { if (total == count) break; total++; if (total > count) { diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 19ef5713718..0600ac1e02a 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -896,6 +896,7 @@ retry: ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMEOUT: + exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE); radlog(L_ERR, " [%s] ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.", inst->xlat_name); ldap_msgfree(*result); return RLM_MODULE_FAIL; @@ -904,6 +905,8 @@ retry: ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMELIMIT_EXCEEDED: + exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE); + case LDAP_BUSY: case LDAP_UNAVAILABLE: /* We don't need to reconnect in these cases so we don't set conn->bound */ @@ -2225,7 +2228,7 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, #ifdef HAVE_LDAP_INITIALIZE DEBUG(" [%s] (re)connect to %s, authentication %d", inst->xlat_name, inst->server, auth); if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) { - exec_trigger(NULL, inst->cs, "modules.ldap.fail"); + exec_trigger(NULL, inst->cs, "modules.ldap.fail", FALSE); radlog(L_ERR, " [%s] ldap_initialize() failed", inst->xlat_name); *result = RLM_MODULE_FAIL; return (NULL); @@ -2234,7 +2237,7 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, } else { DEBUG(" [%s] (re)connect to %s:%d, authentication %d", inst->xlat_name, inst->server, inst->port, auth); if ((ld = ldap_init(inst->server, inst->port)) == NULL) { - exec_trigger(NULL, inst->cs, "modules.ldap.fail"); + exec_trigger(NULL, inst->cs, "modules.ldap.fail", FALSE); radlog(L_ERR, " [%s] ldap_init() failed", inst->xlat_name); *result = RLM_MODULE_FAIL; return (NULL); @@ -2430,7 +2433,7 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, ldap_err2string(ldap_errno)); *result = RLM_MODULE_FAIL; ldap_unbind_s(ld); - exec_trigger(NULL, inst->cs, "modules.ldap.fail"); + exec_trigger(NULL, inst->cs, "modules.ldap.fail", FALSE); return (NULL); } } diff --git a/src/modules/rlm_sql/sql.c b/src/modules/rlm_sql/sql.c index b688c79749e..e7d3d3f3812 100644 --- a/src/modules/rlm_sql/sql.c +++ b/src/modules/rlm_sql/sql.c @@ -51,11 +51,11 @@ static void *sql_conn_create(void *ctx) rcode = (inst->module->sql_init_socket)(sqlsocket, inst->config); if (rcode == 0) { - exec_trigger(NULL, inst->cs, "modules.sql.open"); + exec_trigger(NULL, inst->cs, "modules.sql.open", FALSE); return sqlsocket; } - exec_trigger(NULL, inst->cs, "modules.sql.fail"); + exec_trigger(NULL, inst->cs, "modules.sql.fail", TRUE); free(sqlsocket); return NULL; @@ -67,7 +67,7 @@ static int sql_conn_delete(void *ctx, void *connection) SQL_INST *inst = ctx; SQLSOCK *sqlsocket = connection; - exec_trigger(NULL, inst->cs, "modules.sql.close"); + exec_trigger(NULL, inst->cs, "modules.sql.close", FALSE); if (sqlsocket->conn) { (inst->module->sql_close)(sqlsocket, inst->config);