diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2014-09-20 12:18:49 +0400 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2014-09-20 12:18:49 +0400 |
commit | 62e89248160d3592c2d754fcaa15e37586a5b091 (patch) | |
tree | a6513cfd1e8ef6c6079ea2436e8573b122cc1ec6 /accel-pppd/radius | |
parent | 0a58c20b44136c1fba996becea18696b3f67a1f9 (diff) | |
download | accel-ppp-xebd-62e89248160d3592c2d754fcaa15e37586a5b091.tar.gz accel-ppp-xebd-62e89248160d3592c2d754fcaa15e37586a5b091.zip |
rewrite of authentication/accounting procedures
This patch gets rid of synchronuos style of authentication/accounting.
Synchronous style of authentication/accounting produced sleeping threads
which becomes a problem when lots of sessions started/stopped and all they want authorization/accounting.
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r-- | accel-pppd/radius/acct.c | 654 | ||||
-rw-r--r-- | accel-pppd/radius/auth.c | 492 | ||||
-rw-r--r-- | accel-pppd/radius/packet.c | 11 | ||||
-rw-r--r-- | accel-pppd/radius/radius.c | 70 | ||||
-rw-r--r-- | accel-pppd/radius/radius_p.h | 47 | ||||
-rw-r--r-- | accel-pppd/radius/req.c | 173 | ||||
-rw-r--r-- | accel-pppd/radius/serv.c | 205 |
7 files changed, 860 insertions, 792 deletions
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c index 9a5e549..f991945 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -18,7 +18,6 @@ #include "memdebug.h" -#define STAT_UPDATE_INTERVAL (10 * 60 * 1000) #define INTERIM_SAFE_TIME 10 static int req_set_RA(struct rad_req_t *req, const char *secret) @@ -40,13 +39,13 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) { struct rtnl_link_stats stats; struct radius_pd_t *rpd = req->rpd; - time_t stop_time; + struct timespec ts; int ret = 0; if (ses->stop_time) - stop_time = ses->stop_time; + ts.tv_sec = ses->stop_time; else - time(&stop_time); + clock_gettime(CLOCK_MONOTONIC, &ts); if (ap_session_read_stats(ses, &stats) == 0) { rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", stats.rx_bytes); @@ -58,99 +57,56 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) } else ret = -1; - rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ses->start_time); + rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", ts.tv_sec - ses->start_time); return ret; } -static int rad_acct_read(struct triton_md_handler_t *h) +static void rad_acct_sent(struct rad_req_t *req, int res) { - struct rad_req_t *req = container_of(h, typeof(*req), hnd); - struct rad_packet_t *pack; - int r; - unsigned int dt; - - if (req->reply) { - rad_packet_free(req->reply); - req->reply = NULL; + if (res) { + if (conf_acct_timeout) + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); + else + triton_timer_del(&req->timeout); + return; } - - while (1) { - r = rad_packet_recv(h->fd, &pack, NULL); - - if (pack) { - rad_server_reply(req->serv); - if (req->reply) - rad_packet_free(req->reply); - req->reply = pack; - if (conf_interim_verbose) { - log_ppp_info2("recv "); - rad_packet_print(req->reply, req->serv, log_ppp_info2); - } - } - - if (r) - break; + + __sync_add_and_fetch(&req->serv->stat_interim_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); } - if (!req->reply) - return 0; - - if (req->reply->id != req->pack->id) - return 0; - - rad_server_req_exit(req); + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} - dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + +static void rad_acct_recv(struct rad_req_t *req) +{ + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; stat_accm_add(req->serv->stat_interim_query_1m, dt); stat_accm_add(req->serv->stat_interim_query_5m, dt); - if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) { - rad_packet_free(req->reply); - req->reply = NULL; - } else { - if (req->timeout.tpd) - triton_timer_del(&req->timeout); - } - - triton_md_unregister_handler(h, 1); - - return 1; -} - -static int __rad_req_send(struct rad_req_t *req) -{ - while (1) { - if (rad_server_req_enter(req)) { - if (rad_server_realloc(req)) - return -1; - continue; - } - - if (rad_req_send(req, conf_interim_verbose ? log_ppp_info2 : NULL)) { - rad_server_req_exit(req); - rad_server_fail(req->serv); - continue; - } - - if (!req->hnd.tpd) { - triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); - triton_md_enable_handler(&req->hnd, MD_MODE_READ); - } + triton_timer_del(&req->timeout); - break; - } - - return 0; + triton_md_unregister_handler(&req->hnd, 1); + + rad_packet_free(req->reply); + req->reply = NULL; } static void rad_acct_timeout(struct triton_timer_t *t) { struct rad_req_t *req = container_of(t, typeof(*req), timeout); - time_t ts, dt; - + time_t dt; + struct timespec ts; + rad_server_req_exit(req); rad_server_timeout(req->serv); @@ -164,9 +120,9 @@ static void rad_acct_timeout(struct triton_timer_t *t) return; } - time(&ts); + clock_gettime(CLOCK_MONOTONIC, &ts); - dt = ts - req->rpd->acct_timestamp; + dt = ts.tv_sec - req->ts; if (dt > conf_acct_timeout) { rad_server_fail(req->serv); @@ -176,42 +132,30 @@ static void rad_acct_timeout(struct triton_timer_t *t) ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); return; } - time(&req->rpd->acct_timestamp); } - if (dt > conf_acct_timeout / 2) { - req->timeout.period += 1000; - triton_timer_mod(&req->timeout, 0); - } else if (dt > conf_acct_timeout / 3) { - if (req->timeout.period != conf_timeout * 2000) { - req->timeout.period = conf_timeout * 2000; - triton_timer_mod(&req->timeout, 0); - } + if (dt > conf_acct_timeout / 2) + req->timeout.expire_tv.tv_sec++; + else if (dt > conf_acct_timeout / 4) { + if (req->timeout.expire_tv.tv_sec < conf_timeout * 2) + req->timeout.expire_tv.tv_sec = conf_timeout * 2; } - if (conf_acct_delay_time) { + if (conf_acct_delay_time) req->pack->id++; - rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", dt); - req_set_RA(req, req->serv->secret); - } - - if (__rad_req_send(req)) { - triton_timer_del(t); - - if (conf_acct_timeout) { - log_ppp_warn("radius:acct: no servers available, terminating session...\n"); - ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); - } + + req->try = 0; - return; + if (rad_req_send(req) && conf_acct_timeout) { + log_ppp_warn("radius:acct: no servers available, terminating session...\n"); + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); } - - __sync_add_and_fetch(&req->serv->stat_interim_sent, 1); } static void rad_acct_interim_update(struct triton_timer_t *t) { struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer); + struct timespec ts; if (rpd->acct_req->timeout.tpd) return; @@ -228,281 +172,313 @@ static void rad_acct_interim_update(struct triton_timer_t *t) if (!rpd->acct_interim_interval) return; - time(&rpd->acct_timestamp); + clock_gettime(CLOCK_MONOTONIC, &ts); + rpd->acct_req->ts = ts.tv_sec; rpd->acct_req->pack->id++; - rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Interim-Update"); - if (conf_acct_delay_time) - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", 0); - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + if (!rpd->acct_req->before_send) + req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + + rpd->acct_req->timeout.expire_tv.tv_sec = conf_timeout; + rpd->acct_req->try = 0; - if (__rad_req_send(rpd->acct_req)) - return; + if (rad_req_send(rpd->acct_req) && conf_acct_timeout) { + log_ppp_warn("radius:acct: no servers available, terminating session...\n"); + ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0); + } +} - /* The above call may set rpd->acct_req to NULL in the following chain of events: - 1. __rad_req_send fails (on rad_server_realloc) and calls ppp_terminate; - 2. As a result, an EV_PPP_FINISHING event is fired; - 3. ppp_finishing calls rad_acct_stop that cleans up the request. */ - if (!rpd->acct_req) - return; +static int rad_acct_before_send(struct rad_req_t *req) +{ + struct timespec ts; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_interim_sent, 1); + clock_gettime(CLOCK_MONOTONIC, &ts); + + rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", ts.tv_sec - req->ts); + req_set_RA(req, req->serv->secret); - rpd->acct_req->timeout.period = conf_timeout * 1000; - triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_req->timeout, 0); + return 0; } -int rad_acct_start(struct radius_pd_t *rpd) +static void rad_acct_start_sent(struct rad_req_t *req, int res) { - int i; - time_t ts; - unsigned int dt; + if (res) { + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); + return; + } - if (!conf_accounting) - return 0; + __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); - if (!rpd->acct_req) - rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } - if (!rpd->acct_req) - return -1; + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} - if (rad_req_acct_fill(rpd->acct_req)) { - log_ppp_error("radius:acct: failed to fill accounting attributes\n"); - goto out_err; - } +static void rad_acct_start_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + + stat_accm_add(req->serv->stat_acct_query_1m, dt); + stat_accm_add(req->serv->stat_acct_query_5m, dt); - //if (rad_req_add_val(rpd->acct_req, "Acct-Status-Type", "Start", 4)) - // goto out_err; - //if (rad_req_add_str(rpd->acct_req, "Acct-Session-Id", rpd->ses->ionid, PPP_SESSIONID_LEN, 1)) - // goto out_err; + triton_timer_del(&req->timeout); - if (rpd->acct_req->reply) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; + triton_md_unregister_handler(&req->hnd, 1); + + if (rpd->acct_interim_interval) { + rad_packet_free(req->reply); + req->reply = NULL; + + rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Interim-Update"); + rpd->acct_interim_timer.expire = rad_acct_interim_update; + rpd->acct_interim_timer.period = rpd->acct_interim_interval * 1000; + triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0); + + req->timeout.expire = rad_acct_timeout; + req->recv = rad_acct_recv; + req->sent = rad_acct_sent; + req->log = conf_interim_verbose ? log_ppp_info2 : NULL; + } else { + rad_req_free(rpd->acct_req); + rpd->acct_req = NULL; } - time(&rpd->acct_timestamp); + rpd->acct_started = 1; - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; + ap_session_accounting_started(rpd->ses); +} -#ifdef USE_BACKUP - if (rpd->ses->state != AP_STATE_RESTORE || !rpd->ses->backup->internal) { -#endif - while (1) { - - if (rad_server_req_enter(rpd->acct_req)) { - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_start: no servers available\n"); - goto out_err; - } - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; - continue; - } - - for (i = 0; i < conf_max_try; i++) { - if (conf_acct_delay_time) { - time(&ts); - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp); - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) { - rad_server_req_exit(rpd->acct_req); - goto out_err; - } - } - - if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; - - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1); - - rad_req_wait(rpd->acct_req, conf_timeout); - - if (!rpd->acct_req->reply) { - if (conf_acct_delay_time) - rpd->acct_req->pack->id++; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - continue; - } - - dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 + - (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt); - stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt); - - if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - } else - break; - } - -out: - rad_server_req_exit(rpd->acct_req); - - if (rpd->acct_req->reply) - break; - - rad_server_fail(rpd->acct_req->serv); - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_start: no servers available\n"); - goto out_err; - } - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - goto out_err; - } -#ifdef USE_BACKUP +static void rad_acct_start_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); + stat_accm_add(req->serv->stat_acct_lost_1m, 1); + stat_accm_add(req->serv->stat_acct_lost_5m, 1); + + if (req->before_send) + req->pack->id++; + + if (rad_req_send(req)) + ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0); +} + +int rad_acct_start(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + + if (!req) + return -1; + + if (rad_req_acct_fill(req)) { + log_ppp_error("radius:acct: failed to fill accounting attributes\n"); + goto out_err; } -#endif - close(rpd->acct_req->hnd.fd); - rpd->acct_req->hnd.fd = -1; - rpd->acct_req->hnd.read = rad_acct_read; + if (conf_acct_delay_time) + req->before_send = rad_acct_before_send; + else if (req_set_RA(req, req->serv->secret)) + goto out_err; + + req->recv = rad_acct_start_recv; + req->timeout.expire = rad_acct_start_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->sent = rad_acct_start_sent; + req->log = conf_verbose ? log_ppp_info1 : NULL; - rpd->acct_req->timeout.expire = rad_acct_timeout; - rpd->acct_req->timeout.period = conf_timeout * 1000; + if (rad_req_send(req)) + goto out_err; + + rpd->acct_req = req; - rpd->acct_interim_timer.expire = rad_acct_interim_update; - rpd->acct_interim_timer.period = rpd->acct_interim_interval ? rpd->acct_interim_interval * 1000 : STAT_UPDATE_INTERVAL; - if (rpd->acct_interim_interval) - triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0); return 0; out_err: - rad_req_free(rpd->acct_req); - rpd->acct_req = NULL; + rad_req_free(req); return -1; } -void rad_acct_stop(struct radius_pd_t *rpd) +static void rad_acct_stop_sent(struct rad_req_t *req, int res) { - int i; - time_t ts; - unsigned int dt; - - if (!rpd->acct_req || !rpd->acct_req->serv) + if (res) { + if (req->rpd) + rad_acct_stop_defer(req->rpd); + else { + if (ap_shutdown) + rad_req_free(req); + else + req->try = 0; + } + return; + } + + __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } - if (rpd->acct_interim_timer.tpd) - triton_timer_del(&rpd->acct_interim_timer); + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->timeout, 0); +} - if (rpd->acct_req->timeout.tpd) - rad_server_req_exit(rpd->acct_req); +static void rad_acct_stop_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + + stat_accm_add(req->serv->stat_acct_query_1m, dt); + stat_accm_add(req->serv->stat_acct_query_5m, dt); + + rad_req_free(req); - if (rpd->acct_req->hnd.tpd) - triton_md_unregister_handler(&rpd->acct_req->hnd, 0); + if (rpd) + rpd->acct_req = NULL; +} + +static void rad_acct_stop_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + if (req->active) { + rad_server_req_exit(req); + rad_server_timeout(req->serv); + + __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); + stat_accm_add(req->serv->stat_acct_lost_1m, 1); + stat_accm_add(req->serv->stat_acct_lost_5m, 1); - if (rpd->acct_req->timeout.tpd) - triton_timer_del(&rpd->acct_req->timeout); - - switch (rpd->ses->terminate_cause) { - case TERM_USER_REQUEST: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Request"); - break; - case TERM_SESSION_TIMEOUT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout"); - break; - case TERM_ADMIN_RESET: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset"); - break; - case TERM_USER_ERROR: - case TERM_AUTH_ERROR: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Error"); - break; - case TERM_NAS_ERROR: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error"); - break; - case TERM_NAS_REQUEST: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request"); - break; - case TERM_NAS_REBOOT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot"); - break; - case TERM_LOST_CARRIER: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier"); - break; - case TERM_IDLE_TIMEOUT: - rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout"); - break; + if (req->before_send) + req->pack->id++; + } + + if (req->try == conf_max_try) { + rad_req_free(req); + return; + } + + if (rad_req_send(req)) { + if (ap_shutdown) { + rad_req_free(req); + return; } - rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Stop"); - req_set_stat(rpd->acct_req, rpd->ses); - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); - /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", ""); + req->try = 0; + } +} + +static void start_deferred(struct rad_req_t *req) +{ + if (req->hnd.fd != -1) { + triton_md_register_handler(NULL, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + if (rad_req_read(&req->hnd)) + return; + } + + triton_timer_add(NULL, &req->timeout, 0); +} + +void rad_acct_stop_defer(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rpd->acct_req; + rad_server_req_cancel(req); + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 0); + rpd->acct_req = NULL; + + req->rpd = NULL; + req->log = conf_verbose ? log_info1 : NULL; + req->timeout.expire = rad_acct_stop_timeout; + + triton_context_call(NULL, (triton_event_func)start_deferred, req); +} + +int rad_acct_stop(struct radius_pd_t *rpd) +{ + struct rad_req_t *req = rpd->acct_req; + struct timespec ts; + + if (req) { + triton_timer_del(&rpd->acct_interim_timer); - if (rpd->acct_req->reply) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; - } + rad_server_req_cancel(req); + + clock_gettime(CLOCK_MONOTONIC, &ts); + req->ts = ts.tv_sec; + req->try = 0; + } else { + req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username); + if (!req) + return -1; - time(&rpd->acct_timestamp); - - while (1) { - - if (rad_server_req_enter(rpd->acct_req)) { - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_stop: no servers available\n"); - break; - } - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); - continue; - } - - for(i = 0; i < conf_max_try; i++) { - if (conf_acct_delay_time) { - time(&ts); - rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp); - rpd->acct_req->pack->id++; - if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) - break; - } - if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1); - rad_req_wait(rpd->acct_req, conf_timeout); - if (!rpd->acct_req->reply) { - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - continue; - } - - dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 + - (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt); - stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt); - - if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) { - rad_packet_free(rpd->acct_req->reply); - rpd->acct_req->reply = NULL; - __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1); - stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1); - } else - break; - } - -out: - rad_server_req_exit(rpd->acct_req); - - if (rpd->acct_req->reply) - break; - - rad_server_fail(rpd->acct_req->serv); - if (rad_server_realloc(rpd->acct_req)) { - log_ppp_warn("radius:acct_stop: no servers available\n"); - break; - } - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + if (rad_req_acct_fill(req)) { + log_ppp_error("radius:acct: failed to fill accounting attributes\n"); + rad_req_free(req); + return -1; } - rad_req_free(rpd->acct_req); - rpd->acct_req = NULL; + rpd->acct_req = req; + } + + switch (rpd->ses->terminate_cause) { + case TERM_USER_REQUEST: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Request"); + break; + case TERM_SESSION_TIMEOUT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout"); + break; + case TERM_ADMIN_RESET: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset"); + break; + case TERM_USER_ERROR: + case TERM_AUTH_ERROR: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Error"); + break; + case TERM_NAS_ERROR: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error"); + break; + case TERM_NAS_REQUEST: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request"); + break; + case TERM_NAS_REBOOT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot"); + break; + case TERM_LOST_CARRIER: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier"); + break; + case TERM_IDLE_TIMEOUT: + rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout"); + break; + } + + rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Stop"); + req_set_stat(req, rpd->ses); + req_set_RA(req, req->serv->secret); + + req->recv = rad_acct_stop_recv; + req->timeout.expire = rad_acct_start_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->sent = rad_acct_stop_sent; + req->log = conf_verbose ? log_ppp_info1 : NULL; + + if (rad_req_send(req)) { + rad_acct_stop_defer(rpd); + return -1; + } + + return 0; } diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c index f4efe3b..b73f259 100644 --- a/accel-pppd/radius/auth.c +++ b/accel-pppd/radius/auth.c @@ -4,6 +4,7 @@ #include "crypto.h" #include "triton.h" +#include "mempool.h" #include "events.h" #include "log.h" #include "pwdb.h" @@ -142,193 +143,179 @@ static uint8_t* encrypt_password(const char *passwd, const char *secret, const u return epasswd; } -static int rad_auth_send(struct rad_req_t *req) +static void rad_auth_finalize(struct radius_pd_t *rpd, int r) { - int i; - struct timespec tv, tv2; + hold_pd(rpd); + + rpd->auth_ctx->cb(rpd->auth_ctx->cb_arg, r); + + if (rpd->auth_ctx) { + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } + + release_pd(rpd); +} + +static void rad_auth_recv(struct rad_req_t *req) +{ + struct rad_packet_t *pack = req->reply; unsigned int dt; - int timeout; - while (1) { - if (rad_server_req_enter(req)) { - if (rad_server_realloc(req)) { - log_ppp_warn("radius: no available servers\n"); - break; - } - continue; + triton_timer_del(&req->timeout); + + dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; + stat_accm_add(req->serv->stat_auth_query_1m, dt); + stat_accm_add(req->serv->stat_auth_query_5m, dt); + + if (pack->code == CODE_ACCESS_ACCEPT) { + if (rad_proc_attrs(req)) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; } + + struct ev_radius_t ev = { + .ses = req->rpd->ses, + .request = req->pack, + .reply = pack, + }; + triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); + } + + if (req->rpd->auth_ctx->recv && req->rpd->auth_ctx->recv(req)) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; + } + + req->rpd->authenticated = 1; + + rad_auth_finalize(req->rpd, PWDB_SUCCESS); +} - for(i = 0; i < conf_max_try; i++) { - __sync_add_and_fetch(&req->serv->stat_auth_sent, 1); - clock_gettime(CLOCK_MONOTONIC, &tv); - if (rad_req_send(req, conf_verbose ? log_ppp_info1 : NULL)) - goto out; +static void rad_auth_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + + __sync_add_and_fetch(&req->serv->stat_auth_lost, 1); + stat_accm_add(req->serv->stat_auth_lost_1m, 1); + stat_accm_add(req->serv->stat_auth_lost_5m, 1); - timeout = conf_timeout; + if (rad_req_send(req)) + rad_auth_finalize(req->rpd, PWDB_DENIED); +} - while (timeout > 0) { +static void rad_auth_sent(struct rad_req_t *req, int res) +{ + if (res) { + rad_auth_finalize(req->rpd, PWDB_DENIED); + return; + } + + __sync_add_and_fetch(&req->serv->stat_auth_sent, 1); + + if (!req->hnd.tpd) { + triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } + + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0); +} + +static struct rad_req_t *rad_auth_req_alloc(struct radius_pd_t *rpd, const char *username, int (*recv)(struct rad_req_t *)) +{ + struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + + if (!req) + return NULL; + + if (conf_sid_in_auth) { + if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) + goto out; + } - rad_req_wait(req, timeout); + if (rpd->attr_state) { + if (rad_packet_add_octets(req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) + goto out; + } - if (req->reply) { - if (req->reply->id != req->pack->id) { - rad_packet_free(req->reply); - req->reply = NULL; - clock_gettime(CLOCK_MONOTONIC, &tv2); - timeout = conf_timeout - ((tv2.tv_sec - tv.tv_sec) * 1000 + (tv2.tv_nsec - tv.tv_nsec) / 1000000); - } else - break; - } else - break; - } + req->hnd.read = rad_req_read; + req->timeout.expire = rad_auth_timeout; + req->timeout.expire_tv.tv_sec = conf_timeout; + req->recv = rad_auth_recv; + req->sent = rad_auth_sent; + if (conf_verbose) + req->log = log_ppp_info1; - if (req->reply) { - dt = (req->reply->tv.tv_sec - tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_auth_query_1m, dt); - stat_accm_add(req->serv->stat_auth_query_5m, dt); - break; - } else { - __sync_add_and_fetch(&req->serv->stat_auth_lost, 1); - stat_accm_add(req->serv->stat_auth_lost_1m, 1); - stat_accm_add(req->serv->stat_auth_lost_5m, 1); - } - } -out: - rad_server_req_exit(req); + rpd->auth_ctx->recv = recv; + rpd->auth_ctx->req = req; - if (!req->reply) { - rad_server_fail(req->serv); - if (rad_server_realloc(req)) { - log_ppp_warn("radius: no available servers\n"); - break; - } - } else { - if (req->reply->code == CODE_ACCESS_ACCEPT) { - if (rad_proc_attrs(req)) - return PWDB_DENIED; - return PWDB_SUCCESS; - } else - break; - } - } + return req; - return PWDB_DENIED; +out: + rad_req_free(req); + return NULL; } int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) { - struct rad_req_t *req; - int r = PWDB_DENIED; - //int id = va_arg(args, int); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); + int r; const char *passwd = va_arg(args, const char *); uint8_t *epasswd; int epasswd_len; - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); if (!req) return PWDB_DENIED; epasswd = encrypt_password(passwd, req->serv->secret, req->RA, &epasswd_len); if (!epasswd) - goto out; - - if (rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len)) { - if (epasswd_len) - _free(epasswd); - goto out; - } + return PWDB_DENIED; + r = rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len); if (epasswd_len) _free(epasswd); + + if (r) + return PWDB_DENIED; - if (conf_sid_in_auth) - if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - return -1; - - r = rad_auth_send(req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = req->pack, - .reply = req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - } - -out: - rad_req_free(req); + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); uint8_t chap_password[17]; - int id = va_arg(args, int); uint8_t *challenge = va_arg(args, uint8_t *); int challenge_len = va_arg(args, int); uint8_t *response = va_arg(args, uint8_t *); + + if (!req) + return PWDB_DENIED; chap_password[0] = id; memcpy(chap_password + 1, response, 16); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (challenge_len == 16) - memcpy(rpd->auth_req->RA, challenge, 16); - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) - goto out; + if (challenge_len == 16) + memcpy(req->RA, challenge, 16); - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17)) - goto out; - } else { - if (challenge_len == 16) - memcpy(rpd->auth_req->RA, challenge, 16); - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) - goto out; + if (rad_packet_add_octets(req->pack, NULL, "CHAP-Challenge", challenge, challenge_len)) + return PWDB_DENIED; - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17)) - goto out; - - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } - - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } + if (rad_packet_add_octets(req->pack, NULL, "CHAP-Password", chap_password, 17)) + return PWDB_DENIED; - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; - - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - rpd->auth_req->pack->id++; - } - -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge) @@ -376,11 +363,26 @@ static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge) triton_event_fire(EV_MPPE_KEYS, &ev_mppe); } +static int rad_auth_mschap_v1_recv(struct rad_req_t *req) +{ + if (req->reply->code == CODE_ACCESS_ACCEPT) + setup_mppe(req, req->rpd->auth_ctx->challenge); + else { + struct rad_attr_t *ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error"); + if (ra) { + char **mschap_error = req->rpd->auth_ctx->mschap_error; + *mschap_error = _malloc(ra->len + 1); + memcpy(*mschap_error, ra->val.string, ra->len); + (*mschap_error)[ra->len] = 0; + } + } + + return 0; +} + int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; uint8_t response[50]; - struct rad_attr_t *ra; int id = va_arg(args, int); const uint8_t *challenge = va_arg(args, const uint8_t *); @@ -388,80 +390,70 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar const uint8_t *lm_response = va_arg(args, const uint8_t *); const uint8_t *nt_response = va_arg(args, const uint8_t *); int flags = va_arg(args, int); - char **mschap_error = va_arg(args, char **); + rpd->auth_ctx->mschap_error = va_arg(args, char **); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v1_recv); + + if (!req) + return PWDB_DENIED; + + rpd->auth_ctx->challenge = challenge; response[0] = id; response[1] = flags; memcpy(response + 2, lm_response, 24); memcpy(response + 2 + 24, nt_response, 24); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) - goto out; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) - goto out; - } else { - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) - goto out; - - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) - goto out; + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len)) + return PWDB_DENIED; + + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response))) + return PWDB_DENIED; + + if (rad_req_send(req)) + return PWDB_DENIED; - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } - - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } + return PWDB_WAIT; +} - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; +static int rad_auth_mschap_v2_recv(struct rad_req_t *req) +{ + struct radius_pd_t *rpd = req->rpd; + struct rad_attr_t *ra; + if (req->reply->code == CODE_ACCESS_ACCEPT) { + ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP2-Success"); + if (!ra) { + log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n"); + return -1; + } else + memcpy(rpd->auth_ctx->authenticator, ra->val.octets + 3, 40); - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - setup_mppe(rpd->auth_req, challenge); - rpd->auth_req->pack->id++; - } else if (rpd->auth_req->reply) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error"); + setup_mppe(rpd->auth_ctx->req, NULL); + } else { + ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error"); if (ra) { + char **mschap_error = req->rpd->auth_ctx->mschap_error; *mschap_error = _malloc(ra->len + 1); memcpy(*mschap_error, ra->val.string, ra->len); (*mschap_error)[ra->len] = 0; } - } -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + ra = rad_packet_find_attr(req->reply, NULL, "Reply-Message"); + if (ra) { + char **reply_msg = req->rpd->auth_ctx->reply_msg; + *reply_msg = _malloc(ra->len + 1); + memcpy(*reply_msg, ra->val.string, ra->len); + (*reply_msg)[ra->len] = 0; + } + } - return r; + return 0; } int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args) { - int r = PWDB_DENIED; - struct rad_attr_t *ra; uint8_t mschap_response[50]; + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v2_recv); int id = va_arg(args, int); const uint8_t *challenge = va_arg(args, const uint8_t *); @@ -469,9 +461,12 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar const uint8_t *reserved = va_arg(args, const uint8_t *); const uint8_t *response = va_arg(args, const uint8_t *); int flags = va_arg(args, int); - uint8_t *authenticator = va_arg(args, uint8_t *); - char **mschap_error = va_arg(args, char **); - char **reply_msg = va_arg(args, char **); + rpd->auth_ctx->authenticator = va_arg(args, uint8_t *); + rpd->auth_ctx->mschap_error = va_arg(args, char **); + rpd->auth_ctx->reply_msg = va_arg(args, char **); + + if (!req) + return PWDB_DENIED; mschap_response[0] = id; mschap_response[1] = flags; @@ -479,107 +474,28 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar memcpy(mschap_response + 2 + 16, reserved, 8); memcpy(mschap_response + 2 + 16 + 8, response, 24); - if (!rpd->auth_req) { - rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); - if (!rpd->auth_req) - return PWDB_DENIED; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) - goto out; - - if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) - goto out; - } else { - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) - goto out; + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16)) + return PWDB_DENIED; - if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) - goto out; - - if (rpd->attr_state) { - if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) { - if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } else { - if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len)) - goto out; - } - } + if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response))) + return PWDB_DENIED; - if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA)) - return -1; - } - - if (conf_sid_in_auth) - if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - goto out; - - r = rad_auth_send(rpd->auth_req); - if (r == PWDB_SUCCESS) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP2-Success"); - if (!ra) { - log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n"); - r = PWDB_DENIED; - } else - memcpy(authenticator, ra->val.octets + 3, 40); - } - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = rpd->auth_req->pack, - .reply = rpd->auth_req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - setup_mppe(rpd->auth_req, NULL); - rpd->auth_req->pack->id++; - } else if (rpd->auth_req->reply) { - ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error"); - if (ra) { - *mschap_error = _malloc(ra->len + 1); - memcpy(*mschap_error, ra->val.string, ra->len); - (*mschap_error)[ra->len] = 0; - } - ra = rad_packet_find_attr(rpd->auth_req->reply, NULL, "Reply-Message"); - if (ra) { - *reply_msg = _malloc(ra->len + 1); - memcpy(*reply_msg, ra->val.string, ra->len); - (*reply_msg)[ra->len] = 0; - } - } - -out: - rad_req_free(rpd->auth_req); - rpd->auth_req = NULL; + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } - int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args) { - struct rad_req_t *req; - int r = PWDB_DENIED; - - req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username); + struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL); + if (!req) return PWDB_DENIED; - - if (conf_sid_in_auth) - if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid)) - return -1; - r = rad_auth_send(req); - if (r == PWDB_SUCCESS) { - struct ev_radius_t ev = { - .ses = rpd->ses, - .request = req->pack, - .reply = req->reply, - }; - triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev); - } - - rad_req_free(req); + if (rad_req_send(req)) + return PWDB_DENIED; - return r; + return PWDB_WAIT; } diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c index 5bff60a..87c337f 100644 --- a/accel-pppd/radius/packet.c +++ b/accel-pppd/radius/packet.c @@ -143,13 +143,14 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) else n = read(fd, pack->buf, REQ_LENGTH_MAX); if (n < 0) { - if (errno == EAGAIN) { - rad_packet_free(pack); - return -1; - } + rad_packet_free(pack); + if (errno == EAGAIN) + return 1; + if (errno != ECONNREFUSED) log_ppp_error("radius:packet:read: %s\n", strerror(errno)); - goto out_err; + + return -1; } break; } diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index a3b211e..ec7d911 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -54,6 +54,7 @@ static void *pd_key; static struct ipdb_t ipdb; static mempool_t rpd_pool; +static mempool_t auth_ctx_pool; int rad_proc_attrs(struct rad_req_t *req) { @@ -159,7 +160,7 @@ int rad_proc_attrs(struct rad_req_t *req) return res; } -static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const char *username, int type, va_list _args) +static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, pwdb_callback cb, void *cb_arg, const char *username, int type, va_list _args) { int r = PWDB_NO_IMPL; va_list args; @@ -180,6 +181,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha username1[len + 1 + conf_default_realm_len] = 0; username = username1; } + + rpd->auth_ctx = mempool_alloc(auth_ctx_pool); + memset(rpd->auth_ctx, 0, sizeof(rpd->auth_ctx)); + + rpd->auth_ctx->cb = cb; + rpd->auth_ctx->cb_arg = cb_arg; va_copy(args, _args); @@ -208,8 +215,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha va_end(args); - if (r == PWDB_SUCCESS) - rpd->authenticated = 1; + if (r == PWDB_DENIED) { + if (rpd->auth_ctx->req) + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } return r; } @@ -247,8 +258,6 @@ static struct ipv6db_prefix_t *get_ipv6_prefix(struct ap_session *ses) return NULL; } - - static void session_timeout(struct triton_timer_t *t) { struct radius_pd_t *rpd = container_of(t, typeof(*rpd), session_timeout); @@ -290,6 +299,7 @@ static void ses_starting(struct ap_session *ses) memset(rpd, 0, sizeof(*rpd)); rpd->pd.key = &pd_key; rpd->ses = ses; + rpd->refs = 1; pthread_mutex_init(&rpd->lock, NULL); INIT_LIST_HEAD(&rpd->plugin_list); INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list); @@ -315,6 +325,9 @@ static void ses_acct_start(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); + if (!conf_accounting) + return; + if (!rpd->authenticated) return; @@ -322,26 +335,35 @@ static void ses_acct_start(struct ap_session *ses) ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0); return; } - + + ses->acct_start++; +} + +static void ses_started(struct ap_session *ses) +{ + struct radius_pd_t *rpd = find_pd(ses); + if (rpd->session_timeout.expire_tv.tv_sec) { rpd->session_timeout.expire = session_timeout; triton_timer_add(ses->ctrl->ctx, &rpd->session_timeout, 0); } - + if (rpd->idle_timeout.period) { rpd->idle_timeout.expire = idle_timeout; triton_timer_add(ses->ctrl->ctx, &rpd->idle_timeout, 0); } } + static void ses_finishing(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); - if (!rpd->authenticated) + if (!rpd->acct_started) return; rad_acct_stop(rpd); } + static void ses_finished(struct ap_session *ses) { struct radius_pd_t *rpd = find_pd(ses); @@ -353,11 +375,19 @@ static void ses_finished(struct ap_session *ses) pthread_mutex_unlock(&rpd->lock); pthread_rwlock_unlock(&sessions_lock); - if (rpd->auth_req) - rad_req_free(rpd->auth_req); + if (rpd->auth_ctx) { + rad_server_req_cancel(rpd->auth_ctx->req); + rad_req_free(rpd->auth_ctx->req); + mempool_free(rpd->auth_ctx); + rpd->auth_ctx = NULL; + } - if (rpd->acct_req) - rad_req_free(rpd->acct_req); + if (rpd->acct_req) { + if (rpd->acct_started) + rad_acct_stop_defer(rpd); + else + rad_req_free(rpd->acct_req); + } if (rpd->dm_coa_req) dm_coa_cancel(rpd); @@ -373,7 +403,7 @@ static void ses_finished(struct ap_session *ses) if (rpd->attr_state) _free(rpd->attr_state); - + while (!list_empty(&rpd->ipv6_addr.addr_list)) { a = list_entry(rpd->ipv6_addr.addr_list.next, typeof(*a), entry); list_del(&a->entry); @@ -388,7 +418,7 @@ static void ses_finished(struct ap_session *ses) list_del(&rpd->pd.entry); - mempool_free(rpd); + release_pd(rpd); } struct radius_pd_t *find_pd(struct ap_session *ses) @@ -406,6 +436,16 @@ struct radius_pd_t *find_pd(struct ap_session *ses) abort(); } +void hold_pd(struct radius_pd_t *rpd) +{ + rpd->refs++; +} + +void release_pd(struct radius_pd_t *rpd) +{ + if (--rpd->refs == 0) + mempool_free(rpd); +} struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, const char *port_id, int port, in_addr_t ipaddr, const char *csid) { @@ -650,6 +690,7 @@ static void radius_init(void) struct conf_option_t *opt1; rpd_pool = mempool_create(sizeof(struct radius_pd_t)); + auth_ctx_pool = mempool_create(sizeof(struct radius_auth_ctx)); if (load_config()) _exit(EXIT_FAILURE); @@ -670,6 +711,7 @@ static void radius_init(void) ipdb_register(&ipdb); triton_event_register_handler(EV_SES_STARTING, (triton_event_func)ses_starting); + triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ses_started); triton_event_register_handler(EV_SES_ACCT_START, (triton_event_func)ses_acct_start); triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ses_finishing); triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ses_finished); diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h index 8ad69da..cfb92cd 100644 --- a/accel-pppd/radius/radius_p.h +++ b/accel-pppd/radius/radius_p.h @@ -9,18 +9,32 @@ #include "radius.h" #include "ppp.h" #include "ipdb.h" +#include "pwdb.h" struct rad_server_t; +struct radius_auth_ctx { + struct rad_req_t *req; + pwdb_callback cb; + void *cb_arg; + int (*recv)(struct rad_req_t *); + + const uint8_t *challenge; + uint8_t *authenticator; + char **mschap_error; + char **reply_msg; +}; + struct radius_pd_t { struct list_head entry; struct ap_private pd; struct ap_session *ses; pthread_mutex_t lock; + int refs:8; int authenticated:1; + int acct_started:1; int ipv6_dp_assigned:1; - struct rad_req_t *auth_req; struct rad_req_t *acct_req; struct triton_timer_t acct_interim_timer; @@ -34,7 +48,6 @@ struct radius_pd_t { struct ipv6db_item_t ipv6_addr; struct ipv6db_prefix_t ipv6_dp; int acct_interim_interval; - time_t acct_timestamp; uint8_t *attr_class; int attr_class_len; @@ -42,12 +55,13 @@ struct radius_pd_t { int attr_state_len; int termination_action; + struct radius_auth_ctx *auth_ctx; + struct list_head plugin_list; }; struct rad_req_t { struct list_head entry; - struct triton_context_t ctx; struct triton_md_handler_t hnd; struct triton_timer_t timeout; uint8_t RA[16]; @@ -56,11 +70,21 @@ struct rad_req_t { struct radius_pd_t *rpd; struct rad_server_t *serv; - struct triton_context_t *wait_ctx; in_addr_t server_addr; - int server_port; - int type; + + int server_port:16; + int type:8; + int try:6; + int active:1; + int async:1; + + time_t ts; + + void (*recv)(struct rad_req_t *); + int (*before_send)(struct rad_req_t *); + int (*send)(struct rad_req_t *, int async); + void (*sent)(struct rad_req_t *, int res); void (*log)(const char *fmt, ...); }; @@ -149,13 +173,16 @@ void rad_dict_free(struct rad_dict_t *dict); struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username); struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port); +struct rad_req_t *rad_req_alloc_empty(); int rad_req_acct_fill(struct rad_req_t *); void rad_req_free(struct rad_req_t *); -int rad_req_send(struct rad_req_t *req, void (*log)(const char *fmt, ...)); -int rad_req_wait(struct rad_req_t *, int); +int rad_req_send(struct rad_req_t *req); +int rad_req_read(struct triton_md_handler_t *h); struct radius_pd_t *find_pd(struct ap_session *ses); int rad_proc_attrs(struct rad_req_t *req); +void hold_pd(struct radius_pd_t *rpd); +void release_pd(struct radius_pd_t *rpd); int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args); int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args); @@ -164,7 +191,8 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args); int rad_acct_start(struct radius_pd_t *rpd); -void rad_acct_stop(struct radius_pd_t *rpd); +int rad_acct_stop(struct radius_pd_t *rpd); +void rad_acct_stop_defer(struct radius_pd_t *rpd); struct rad_packet_t *rad_packet_alloc(int code); int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA); @@ -180,6 +208,7 @@ struct rad_server_t *rad_server_get2(int, in_addr_t, int); void rad_server_put(struct rad_server_t *, int); int rad_server_req_enter(struct rad_req_t *); void rad_server_req_exit(struct rad_req_t *); +int rad_server_req_cancel(struct rad_req_t *); int rad_server_realloc(struct rad_req_t *); void rad_server_fail(struct rad_server_t *); void rad_server_timeout(struct rad_server_t *); diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c index 27a33f2..172fb1c 100644 --- a/accel-pppd/radius/req.c +++ b/accel-pppd/radius/req.c @@ -4,25 +4,26 @@ #include <errno.h> #include <fcntl.h> #include <unistd.h> -#include <sched.h> +#include <assert.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "log.h" #include "radius_p.h" +#include "mempool.h" #include "memdebug.h" -static int rad_req_read(struct triton_md_handler_t *h); -static void rad_req_timeout(struct triton_timer_t *t); static int make_socket(struct rad_req_t *req); +static mempool_t req_pool; static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port) { struct rad_plugin_t *plugin; struct ppp_t *ppp = NULL; - struct rad_req_t *req = _malloc(sizeof(*req)); + struct rad_req_t *req = mempool_alloc(req_pool); + struct timespec ts; if (!req) { log_emerg("radius: out of memory\n"); @@ -32,10 +33,13 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons if (rpd->ses->ctrl->ppp) ppp = container_of(rpd->ses, typeof(*ppp), ses); + clock_gettime(CLOCK_MONOTONIC, &ts); + memset(req, 0, sizeof(*req)); req->rpd = rpd; req->hnd.fd = -1; - req->ctx.before_switch = log_switch; + req->hnd.read = rad_req_read; + req->ts = ts.tv_sec; req->type = code == CODE_ACCESS_REQUEST ? RAD_SERV_AUTH : RAD_SERV_ACCT; @@ -161,6 +165,21 @@ struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char * return req; } +struct rad_req_t *rad_req_alloc_empty() +{ + struct rad_req_t *req = mempool_alloc(req_pool); + + if (!req) { + log_emerg("radius: out of memory\n"); + return NULL; + } + + memset(req, 0, sizeof(*req)); + req->hnd.fd = -1; + + return req; +} + int rad_req_acct_fill(struct rad_req_t *req) { struct ipv6db_addr_t *a; @@ -211,15 +230,26 @@ int rad_req_acct_fill(struct rad_req_t *req) void rad_req_free(struct rad_req_t *req) { + assert(!req->active); + if (req->serv) rad_server_put(req->serv, req->type); - if (req->hnd.fd >= 0 ) + + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 1); + else if (req->hnd.fd != -1) close(req->hnd.fd); + + if (req->timeout.tpd) + triton_timer_del(&req->timeout); + if (req->pack) rad_packet_free(req->pack); + if (req->reply) rad_packet_free(req->reply); - _free(req); + + mempool_free(req); } static int make_socket(struct rad_req_t *req) @@ -231,7 +261,7 @@ static int make_socket(struct rad_req_t *req) log_ppp_error("radius:socket: %s\n", strerror(errno)); return -1; } - + fcntl(req->hnd.fd, F_SETFD, fcntl(req->hnd.fd, F_GETFD) | FD_CLOEXEC); memset(&addr, 0, sizeof(addr)); @@ -270,95 +300,120 @@ out_err: return -1; } -int rad_req_send(struct rad_req_t *req, void (*log)(const char *fmt, ...)) +static int __rad_req_send(struct rad_req_t *req, int async) { + if (async == -1) { + req->try = conf_max_try - 1; + rad_req_send(req); + return 0; + } + if (req->hnd.fd == -1 && make_socket(req)) return -1; + + if (req->before_send && req->before_send(req)) + goto out_err; if (!req->pack->buf && rad_packet_build(req->pack, req->RA)) goto out_err; - if (log) { - log("send "); - rad_packet_print(req->pack, req->serv, log); + if (req->log) { + req->log("send "); + rad_packet_print(req->pack, req->serv, req->log); } + + if (req->sent) + req->sent(req, 0); rad_packet_send(req->pack, req->hnd.fd, NULL); return 0; out_err: - close(req->hnd.fd); - req->hnd.fd = -1; + if (req->hnd.tpd) + triton_md_unregister_handler(&req->hnd, 1); + else { + close(req->hnd.fd); + req->hnd.fd = -1; + } + + if (async && req->sent) + req->sent(req, -1); + return -1; } -static void req_wakeup(struct rad_req_t *req) -{ - struct triton_context_t *ctx = req->wait_ctx; - if (req->timeout.tpd) - triton_timer_del(&req->timeout); - triton_md_unregister_handler(&req->hnd, 0); - triton_context_unregister(&req->ctx); - triton_context_wakeup(ctx); -} -static int rad_req_read(struct triton_md_handler_t *h) +int rad_req_send(struct rad_req_t *req) { - struct rad_req_t *req = container_of(h, typeof(*req), hnd); - struct rad_packet_t *pack; int r; - while (1) { - r = rad_packet_recv(h->fd, &pack, NULL); - - if (pack) { - if (req->reply) - rad_packet_free(req->reply); - req->reply = pack; + req->send = __rad_req_send; + + if (req->try++ == conf_max_try) { + rad_server_req_exit(req); + rad_server_fail(req->serv); + + if (rad_server_realloc(req)) { + if (req->rpd) + log_ppp_warn("radius: no available servers\n"); + return -1; } - if (r) - break; + req->try = 1; } - req_wakeup(req); - - return 1; -} -static void rad_req_timeout(struct triton_timer_t *t) -{ - struct rad_req_t *req = container_of(t, typeof(*req), timeout); - - req_wakeup(req); + if (!req->active) { + while (1) { + r = rad_server_req_enter(req); + + if (r >= 0) + break; + + if (rad_server_realloc(req)) { + if (req->rpd) + log_ppp_warn("radius: no available servers\n"); + return -1; + } + } + } else + r = __rad_req_send(req, 0); + + return r; } -int rad_req_wait(struct rad_req_t *req, int timeout) +int rad_req_read(struct triton_md_handler_t *h) { - req->wait_ctx = triton_context_self(); - req->hnd.read = rad_req_read; - req->timeout.expire = rad_req_timeout; - - triton_context_register(&req->ctx, req->rpd ? req->rpd->ses : NULL); - triton_context_set_priority(&req->ctx, 1); - triton_md_register_handler(&req->ctx, &req->hnd); - triton_md_enable_handler(&req->hnd, MD_MODE_READ); + struct rad_req_t *req = container_of(h, typeof(*req), hnd); + struct rad_packet_t *pack; - req->timeout.period = timeout * 1000; - triton_timer_add(&req->ctx, &req->timeout, 0); + while (1) { + if (rad_packet_recv(h->fd, &pack, NULL)) + return 0; + + if (pack->id == req->pack->id) + break; + + rad_packet_free(req->reply); + } - triton_context_wakeup(&req->ctx); + req->reply = pack; - triton_context_schedule(); + rad_server_req_exit(req); - if (req->log && req->reply) { + if (req->log) { req->log("recv "); rad_packet_print(req->reply, req->serv, req->log); } - return 0; + + if (req->recv) + req->recv(req); + + return 1; } static void req_init(void) { + req_pool = mempool_create(sizeof(struct rad_req_t)); } DEFINE_INIT(50, req_init); diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c index 0910314..6c01a88 100644 --- a/accel-pppd/radius/serv.c +++ b/accel-pppd/radius/serv.c @@ -100,6 +100,48 @@ void rad_server_put(struct rad_server_t *s, int type) } } +static void req_wakeup(struct rad_req_t *req) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + pthread_mutex_lock(&req->serv->lock); + + if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) { + req->active = 0; + req->serv->req_cnt--; + pthread_mutex_unlock(&req->serv->lock); + + req->send(req, -1); + + return; + } + pthread_mutex_unlock(&req->serv->lock); + + req->send(req, 1); +} + +int rad_server_req_cancel(struct rad_req_t *req) +{ + int r = 0; + + pthread_mutex_lock(&req->serv->lock); + if (req->entry.next) { + list_del(&req->entry); + req->serv->queue_cnt--; + r = 1; + } + pthread_mutex_unlock(&req->serv->lock); + + rad_server_req_exit(req); + + if (req->timeout.tpd) + triton_timer_del(&req->timeout); + + return r; +} + int rad_server_req_enter(struct rad_req_t *req) { struct timespec ts; @@ -112,8 +154,13 @@ int rad_server_req_enter(struct rad_req_t *req) if (ts.tv_sec < req->serv->fail_time) return -1; - if (!req->serv->req_limit) + if (!req->serv->req_limit) { + if (req->send) + return req->send(req, 0); return 0; + } + + assert(!req->active); pthread_mutex_lock(&req->serv->lock); @@ -123,46 +170,47 @@ int rad_server_req_enter(struct rad_req_t *req) } if (req->serv->req_cnt >= req->serv->req_limit) { - list_add_tail(&req->entry, &req->serv->req_queue); - req->serv->queue_cnt++; - - pthread_mutex_unlock(&req->serv->lock); - triton_context_schedule(); - pthread_mutex_lock(&req->serv->lock); - - req->serv->queue_cnt--; - if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) { + if (req->send) { + list_add_tail(&req->entry, &req->serv->req_queue); + req->serv->queue_cnt++; pthread_mutex_unlock(&req->serv->lock); - return -1; + return 0; } + + pthread_mutex_unlock(&req->serv->lock); + return 1; } req->serv->req_cnt++; log_ppp_debug("radius(%i): req_enter %i\n", req->serv->id, req->serv->req_cnt); pthread_mutex_unlock(&req->serv->lock); + + req->active = 1; return 0; } void rad_server_req_exit(struct rad_req_t *req) { - struct rad_req_t *r = NULL; - if (!req->serv->req_limit) return; + assert(req->active); + + req->active = 0; + pthread_mutex_lock(&req->serv->lock); req->serv->req_cnt--; log_ppp_debug("radius(%i): req_exit %i\n", req->serv->id, req->serv->req_cnt); assert(req->serv->req_cnt >= 0); if (req->serv->req_cnt < req->serv->req_limit && !list_empty(&req->serv->req_queue)) { - r = list_entry(req->serv->req_queue.next, typeof(*r), entry); + struct rad_req_t *r = list_entry(req->serv->req_queue.next, typeof(*r), entry); list_del(&r->entry); + req->serv->queue_cnt--; + req->active = 1; + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } pthread_mutex_unlock(&req->serv->lock); - - if (r) - triton_context_wakeup(r->rpd->ses->ctrl->ctx); } int rad_server_realloc(struct rad_req_t *req) @@ -214,7 +262,7 @@ void rad_server_fail(struct rad_server_t *s) while (!list_empty(&s->req_queue)) { r = list_entry(s->req_queue.next, typeof(*r), entry); list_del(&r->entry); - triton_context_wakeup(r->rpd->ses->ctrl->ctx); + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } } @@ -223,7 +271,7 @@ void rad_server_fail(struct rad_server_t *s) void rad_server_timeout(struct rad_server_t *s) { - if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try) + if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try * 3) rad_server_fail(s); } @@ -248,13 +296,49 @@ static int req_set_RA(struct rad_req_t *req, const char *secret) return 0; } +static void acct_on_sent(struct rad_req_t *req, int res) +{ + if (!res && !req->hnd.tpd) { + triton_md_register_handler(&req->serv->ctx, &req->hnd); + triton_md_enable_handler(&req->hnd, MD_MODE_READ); + } +} + +static void acct_on_recv(struct rad_req_t *req) +{ + struct rad_server_t *s = req->serv; + + rad_req_free(req); + + if (req->serv->starting) { + req->serv->starting = 0; + req->serv->acct_on = 1; + } else + __free_server(s); +} + +static void acct_on_timeout(struct triton_timer_t *t) +{ + struct rad_req_t *req = container_of(t, typeof(*req), timeout); + struct rad_server_t *s = req->serv; + + if (!s->starting && ++req->serv->req_cnt == conf_max_try) { + rad_req_free(req); + __free_server(s); + return; + } + + req->try = 1; + + rad_req_send(req); +} + static void send_acct_on(struct rad_server_t *s) { struct rad_req_t *req = _malloc(sizeof(*req)); - int i; if (!req) - goto out_err; + return; memset(req, 0, sizeof(*req)); req->hnd.fd = -1; @@ -262,6 +346,12 @@ static void send_acct_on(struct rad_server_t *s) req->server_addr = s->addr; req->server_port = s->acct_port; req->serv = s; + req->sent = acct_on_sent; + req->recv = acct_on_recv; + req->hnd.read = rad_req_read; + req->timeout.expire = acct_on_timeout; + req->timeout.period = conf_timeout * 1000; + req->try = 1; __sync_add_and_fetch(&s->client_cnt[req->type], 1); if (conf_verbose) req->log = log_info1; @@ -284,55 +374,14 @@ static void send_acct_on(struct rad_server_t *s) if (req_set_RA(req, s->secret)) goto out_err; - for (i = 0; i < conf_max_try; i++) { - if (rad_req_send(req, conf_verbose ? log_info1 : NULL)) - goto out_err; - - rad_req_wait(req, conf_timeout); - - if (!s->starting) - break; + rad_req_send(req); - if (!req->reply) - continue; - - if (req->reply->id == req->pack->id && req->reply->code == CODE_ACCOUNTING_RESPONSE) { - s->starting = 0; - s->acct_on = 1; - break; - } - - rad_packet_free(req->reply); - req->reply = NULL; - } - - if (!s->starting) { - if (s->timer.tpd) - triton_timer_del(&s->timer); - - if (!s->acct_on) - triton_context_unregister(&s->ctx); - - rad_req_free(req); + triton_timer_add(&s->ctx, &req->timeout, 0); - return; - } + return; out_err: - if (req) - rad_req_free(req); - - if (s->timer.tpd) - triton_timer_mod(&s->timer, 0); - else - triton_timer_add(&s->ctx, &s->timer, 0); -} - -static void restart_acct_on(struct triton_timer_t *t) -{ - struct rad_server_t *s = container_of(t, typeof(*s), timer); - - send_acct_on(s); + rad_req_free(req); } static void serv_ctx_close(struct triton_context_t *ctx) @@ -444,6 +493,14 @@ static void __add_server(struct rad_server_t *s) s->stat_interim_lost_5m = stat_accm_create(5 * 60); s->stat_interim_query_1m = stat_accm_create(60); s->stat_interim_query_5m = stat_accm_create(5 * 60); + + s->ctx.close = serv_ctx_close; + + triton_context_register(&s->ctx, NULL); + triton_context_set_priority(&s->ctx, 1); + if (conf_acct_on) + triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s); + triton_context_wakeup(&s->ctx); } static void __free_server(struct rad_server_t *s) @@ -465,6 +522,8 @@ static void __free_server(struct rad_server_t *s) stat_accm_free(s->stat_interim_query_1m); stat_accm_free(s->stat_interim_query_5m); + triton_context_unregister(&s->ctx); + _free(s); } @@ -732,7 +791,7 @@ static void load_config(void) while (!list_empty(&s->req_queue)) { r = list_entry(s->req_queue.next, typeof(*r), entry); list_del(&r->entry); - triton_context_wakeup(r->rpd->ses->ctrl->ctx); + triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r); } if (!s->client_cnt[0] && !s->client_cnt[1]) { @@ -756,18 +815,8 @@ static void load_config(void) list_for_each_entry(s, &serv_list, entry) { if (s->starting) { - if (!conf_accounting || !s->acct_port) + if (!conf_accounting || !s->auth_port) s->starting = 0; - else { - s->ctx.close = serv_ctx_close; - s->timer.expire = restart_acct_on; - s->timer.expire_tv.tv_sec = 10; - - triton_context_register(&s->ctx, NULL); - triton_context_set_priority(&s->ctx, 1); - triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s); - triton_context_wakeup(&s->ctx); - } } } } |